From f480a6c373b5601477b75a588547ae90c6147467 Mon Sep 17 00:00:00 2001 From: Chris Kaczor Date: Fri, 10 Mar 2023 12:18:03 -0500 Subject: [PATCH] Start modernization --- Application/App.xaml.cs | 9 + Application/BrowserCommon.cs | 12 +- Application/Category.cs | 27 - Application/Data/Database.cs | 163 ++-- Application/Data/RealmObservableCollection.cs | 29 + Application/Database/Template.sdf | Bin 131072 -> 0 bytes Application/Entities.cs | 191 ++--- Application/Feed.cs | 59 -- Application/FeedAction.cs | 26 - Application/FeedCenter.csproj | 393 +--------- Application/FeedCenterEntities.datasource | 10 - Application/FeedCenterEntities1.datasource | 10 - Application/FeedCenterEntities2.datasource | 10 - Application/FeedErrorWindow.xaml.cs | 7 +- Application/FeedItem.cs | 38 - Application/FeedParsers/FeedParserBase.cs | 6 +- Application/FeedParsers/RdfParser.cs | 8 +- Application/FeedParsers/RssParser.cs | 8 +- Application/Feeds/Category.cs | 22 +- Application/Feeds/Feed.cs | 189 ++--- Application/Feeds/FeedAction.cs | 25 - Application/Feeds/FeedItem.cs | 34 +- Application/FodyWeavers.xml | 3 + Application/FodyWeavers.xsd | 34 + Application/MainWindow/CategoryList.cs | 19 +- Application/MainWindow/DragDrop.cs | 7 +- Application/MainWindow/FeedCreation.cs | 12 +- Application/MainWindow/FeedList.cs | 26 +- Application/MainWindow/FeedReading.cs | 19 +- Application/MainWindow/MainWindow.xaml.cs | 34 +- Application/MainWindow/Toolbar.cs | 20 +- Application/MainWindow/WindowHandler.cs | 11 +- Application/Model.Context.cs | 34 - Application/Model.Context.tt | 636 --------------- Application/Model.Designer.cs | 10 - Application/Model.cs | 9 - Application/Model.edmx | 383 --------- Application/Model.tt | 726 ------------------ Application/NotificationIcon.cs | 2 +- Application/Options/AboutOptionsPanel.xaml.cs | 2 +- Application/Options/BulkFeedWindow.xaml.cs | 2 +- Application/Options/FeedWindow.xaml | 44 +- Application/Options/FeedWindow.xaml.cs | 7 +- Application/Options/FeedsOptionsPanel.xaml.cs | 13 +- Application/Options/OptionsWindow.xaml.cs | 11 +- Application/Options/Setting.cs | 14 + Application/Properties/AssemblyInfo.cs | 3 + Application/Properties/Resources.Designer.cs | 2 +- Application/Properties/Settings.Designer.cs | 2 +- Application/Properties/launchSettings.json | 8 + Application/Setting.cs | 21 - Application/SettingsStore.cs | 72 +- Application/SplashWindow.xaml.cs | 27 +- Application/app.config | 33 +- Application/packages.config | 8 - FeedCenter.sln | 46 +- FeedCenter.sln.DotSettings | 6 + 57 files changed, 661 insertions(+), 2921 deletions(-) delete mode 100644 Application/Category.cs create mode 100644 Application/Data/RealmObservableCollection.cs delete mode 100644 Application/Database/Template.sdf delete mode 100644 Application/Feed.cs delete mode 100644 Application/FeedAction.cs delete mode 100644 Application/FeedCenterEntities.datasource delete mode 100644 Application/FeedCenterEntities1.datasource delete mode 100644 Application/FeedCenterEntities2.datasource delete mode 100644 Application/FeedItem.cs delete mode 100644 Application/Feeds/FeedAction.cs create mode 100644 Application/FodyWeavers.xml create mode 100644 Application/FodyWeavers.xsd delete mode 100644 Application/Model.Context.cs delete mode 100644 Application/Model.Context.tt delete mode 100644 Application/Model.Designer.cs delete mode 100644 Application/Model.cs delete mode 100644 Application/Model.edmx delete mode 100644 Application/Model.tt create mode 100644 Application/Options/Setting.cs create mode 100644 Application/Properties/launchSettings.json delete mode 100644 Application/Setting.cs delete mode 100644 Application/packages.config create mode 100644 FeedCenter.sln.DotSettings diff --git a/Application/App.xaml.cs b/Application/App.xaml.cs index 8ac0960..c71e977 100644 --- a/Application/App.xaml.cs +++ b/Application/App.xaml.cs @@ -3,6 +3,7 @@ using Common.Helpers; using Common.IO; using Common.Settings; using Common.Wpf.Extensions; +using FeedCenter.Data; using FeedCenter.Properties; using System; using System.Diagnostics; @@ -49,6 +50,14 @@ namespace FeedCenter // Set the data directory based on debug or not AppDomain.CurrentDomain.SetData("DataDirectory", SystemConfiguration.DataDirectory); + // Get the data directory + var path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString(); + + // Set the path + Database.DatabasePath = path; + Database.DatabaseFile = System.IO.Path.Combine(path, Settings.Default.DatabaseFile); + Database.Load(); + // Get the generic provider var genericProvider = (GenericSettingsProvider) Settings.Default.Providers[typeof(GenericSettingsProvider).Name]; diff --git a/Application/BrowserCommon.cs b/Application/BrowserCommon.cs index dd4f1ab..9ead038 100644 --- a/Application/BrowserCommon.cs +++ b/Application/BrowserCommon.cs @@ -28,7 +28,7 @@ namespace FeedCenter public static bool OpenLink(string url) { // Get the browser - Browser browser = FindBrowser(Settings.Default.Browser); + var browser = FindBrowser(Settings.Default.Browser); // Start the browser return OpenLink(browser, url); @@ -47,7 +47,15 @@ namespace FeedCenter // Start the browser if (browser == null) - Process.Start(url); + { + var ps = new ProcessStartInfo(url) + { + UseShellExecute = true, + Verb = "open" + }; + + Process.Start(ps); + } else Process.Start(browser.Command, url); diff --git a/Application/Category.cs b/Application/Category.cs deleted file mode 100644 index 9083a4d..0000000 --- a/Application/Category.cs +++ /dev/null @@ -1,27 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FeedCenter -{ - using System; - using System.Collections.Generic; - - public partial class Category - { - public Category() - { - this.Feeds = new HashSet(); - } - - public System.Guid ID { get; set; } - public string Name { get; set; } - - public virtual ICollection Feeds { get; set; } - } -} diff --git a/Application/Data/Database.cs b/Application/Data/Database.cs index 03f7e21..c7c16bf 100644 --- a/Application/Data/Database.cs +++ b/Application/Data/Database.cs @@ -12,12 +12,15 @@ namespace FeedCenter.Data { #region Static database settings + public static string DatabaseFile; public static string DatabasePath; #endregion #region File version + public static FeedCenterEntities Entities; + private enum SqlServerCeFileVersion { Unknown, @@ -27,6 +30,11 @@ namespace FeedCenter.Data Version40, } + public static void Load() + { + Entities = new FeedCenterEntities(); + } + private static SqlServerCeFileVersion GetFileVersion(string databasePath) { // Create a mapping of version numbers to the version enumeration @@ -43,18 +51,15 @@ namespace FeedCenter.Data try { // Open the database file - using (var stream = new FileStream(databasePath, FileMode.Open, FileAccess.Read)) - { - // Read the file using the binary reader - var reader = new BinaryReader(stream); + using var stream = new FileStream(databasePath, FileMode.Open, FileAccess.Read); + // Read the file using the binary reader + var reader = new BinaryReader(stream); - // Seek to the version signature - stream.Seek(16, SeekOrigin.Begin); + // Seek to the version signature + stream.Seek(16, SeekOrigin.Begin); - // Read the version signature - signature = reader.ReadInt32(); - - } + // Read the version signature + signature = reader.ReadInt32(); } catch (Exception exception) { @@ -69,25 +74,23 @@ namespace FeedCenter.Data #endregion - public static bool DatabaseExists => File.Exists(DatabasePath); + public static bool DatabaseExists => File.Exists(DatabaseFile); public static void CreateDatabase() { Tracer.WriteLine("Creating database engine"); // Create the database engine - using (var engine = new SqlCeEngine($"Data Source={DatabasePath}")) - { - Tracer.WriteLine("Creating database"); + using var engine = new SqlCeEngine($"Data Source={DatabaseFile}"); + Tracer.WriteLine("Creating database"); - // Create the database itself - engine.CreateDatabase(); + // Create the database itself + engine.CreateDatabase(); - Tracer.WriteLine("Running database script"); + Tracer.WriteLine("Running database script"); - // Run the creation script - ExecuteScript(Resources.CreateDatabase); - } + // Run the creation script + ExecuteScript(Resources.CreateDatabase); } private static int GetVersion(SqlCeConnection connection) @@ -97,14 +100,14 @@ namespace FeedCenter.Data try { // Check the database version table - using (var command = new SqlCeCommand("SELECT Value FROM DatabaseVersion", connection)) - versionString = command.ExecuteScalar().ToString(); + using var command = new SqlCeCommand("SELECT Value FROM DatabaseVersion", connection); + versionString = command.ExecuteScalar().ToString(); } catch (SqlCeException) { // Check the setting table for the version - using (var command = new SqlCeCommand("SELECT Value FROM Setting WHERE Name = 'DatabaseVersion'", connection)) - versionString = command.ExecuteScalar().ToString(); + using var command = new SqlCeCommand("SELECT Value FROM Setting WHERE Name = 'DatabaseVersion'", connection); + versionString = command.ExecuteScalar().ToString(); } if (string.IsNullOrEmpty(versionString)) @@ -120,7 +123,7 @@ namespace FeedCenter.Data Tracer.WriteLine("Getting database file version"); // Get the database file version - var fileVersion = GetFileVersion(DatabasePath); + var fileVersion = GetFileVersion(DatabaseFile); Tracer.WriteLine("Database file version: {0}", fileVersion); @@ -130,54 +133,50 @@ namespace FeedCenter.Data Tracer.WriteLine("Creating database engine"); // Create the database engine - using (var engine = new SqlCeEngine($"Data Source={DatabasePath}")) - { - Tracer.WriteLine("Upgrading database"); + using var engine = new SqlCeEngine($"Data Source={DatabaseFile}"); + Tracer.WriteLine("Upgrading database"); - // Upgrade the database (if needed) - engine.Upgrade(); - } + // Upgrade the database (if needed) + engine.Upgrade(); } Tracer.WriteLine("Getting database version"); // Create a database connection - using (var connection = new SqlCeConnection($"Data Source={DatabasePath}")) + using var connection = new SqlCeConnection($"Data Source={DatabaseFile}"); + // Open the connection + connection.Open(); + + // Get the database version + var databaseVersion = GetVersion(connection); + + // Create a dictionary of database upgrade scripts and their version numbers + var scriptList = new Dictionary(); + + // Loop over the properties of the resource object looking for update scripts + foreach (var property in typeof(Resources).GetProperties().Where(property => property.Name.StartsWith("DatabaseUpdate"))) { - // Open the connection - connection.Open(); + // Get the name of the property + var propertyName = property.Name; - // Get the database version - var databaseVersion = GetVersion(connection); + // Extract the version from the name + var version = int.Parse(propertyName.Substring(propertyName.IndexOf("_", StringComparison.Ordinal) + 1)); - // Create a dictionary of database upgrade scripts and their version numbers - var scriptList = new Dictionary(); + // Add to the script list + scriptList[version] = propertyName; + } - // Loop over the properties of the resource object looking for update scripts - foreach (var property in typeof(Resources).GetProperties().Where(property => property.Name.StartsWith("DatabaseUpdate"))) + // Loop over the scripts ordered by version + foreach (var pair in scriptList.OrderBy(pair => pair.Key)) + { + // If the database version is less than or equal to the script version the script needs to run + if (databaseVersion <= pair.Key) { - // Get the name of the property - var propertyName = property.Name; + // Get the script text + var scriptText = Resources.ResourceManager.GetString(pair.Value); - // Extract the version from the name - var version = int.Parse(propertyName.Substring(propertyName.IndexOf("_", StringComparison.Ordinal) + 1)); - - // Add to the script list - scriptList[version] = propertyName; - } - - // Loop over the scripts ordered by version - foreach (var pair in scriptList.OrderBy(pair => pair.Key)) - { - // If the database version is less than or equal to the script version the script needs to run - if (databaseVersion <= pair.Key) - { - // Get the script text - var scriptText = Resources.ResourceManager.GetString(pair.Value); - - // Run the script - ExecuteScript(scriptText); - } + // Run the script + ExecuteScript(scriptText); } } } @@ -187,36 +186,32 @@ namespace FeedCenter.Data Tracer.WriteLine("Creating database engine"); // Create the database engine - using (var engine = new SqlCeEngine($"Data Source={DatabasePath}")) - { - Tracer.WriteLine("Shrinking database"); + using var engine = new SqlCeEngine($"Data Source={DatabaseFile}"); + Tracer.WriteLine("Shrinking database"); - // Compact the database - engine.Shrink(); - } + // Compact the database + engine.Shrink(); } private static void ExecuteScript(string scriptText) { // Create a database connection - using (var connection = new SqlCeConnection($"Data Source={DatabasePath}")) + using var connection = new SqlCeConnection($"Data Source={DatabaseFile}"); + // Open the connection + connection.Open(); + + // Setup the delimiters + var delimiters = new[] { "\r\nGO\r\n" }; + + // Split the script at the delimiters + var statements = scriptText.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); + + // Loop over each statement in the script + foreach (var statement in statements) { - // Open the connection - connection.Open(); - - // Setup the delimiters - var delimiters = new[] { "\r\nGO\r\n" }; - - // Split the script at the delimiters - var statements = scriptText.Split(delimiters, StringSplitOptions.RemoveEmptyEntries); - - // Loop over each statement in the script - foreach (var statement in statements) - { - // Execute the statement - using (var command = new SqlCeCommand(statement, connection)) - command.ExecuteNonQuery(); - } + // Execute the statement + using var command = new SqlCeCommand(statement, connection); + command.ExecuteNonQuery(); } } } diff --git a/Application/Data/RealmObservableCollection.cs b/Application/Data/RealmObservableCollection.cs new file mode 100644 index 0000000..02eef85 --- /dev/null +++ b/Application/Data/RealmObservableCollection.cs @@ -0,0 +1,29 @@ +using Realms; +using System.Collections.ObjectModel; +using System.Collections.Specialized; + +namespace FeedCenter.Data +{ + public class RealmObservableCollection : ObservableCollection where T : IRealmObject + { + private readonly Realm _realm; + + public RealmObservableCollection(Realm realm) : base(realm.All()) + { + _realm = realm; + } + + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (e.OldItems != null) + foreach (T item in e.OldItems) + _realm.Remove(item); + + if (e.NewItems != null) + foreach (T item in e.NewItems) + _realm.Add(item); + + base.OnCollectionChanged(e); + } + } +} diff --git a/Application/Database/Template.sdf b/Application/Database/Template.sdf deleted file mode 100644 index 6f98ad360300f8689dc7492c4c6ae83c0dd0a9fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131072 zcmeI53ve98na6v3wJ%A#dRek9%ks)k`4Nzeu`!QW!YkS4Wy>}OjstmZtwBbXB};p>@7J&Cp6T`(w=BDx(cu?=#1XlG`RHe{_(O;B!yXCc`r4vm>BJk z@1e%)IY@eZ6`g?8t|J-S=-*WnAPXWu00d4hfh$k0ct{5U5C8!X009sH0T2KI_Tr>_ zr|0EuW;Ylt{Kk;q9FuNtU`@=|)E!EM60!c+v-Iz_SR{6KtR|Kp+ZXHi(ZQO!>4MW` zO>7R`-Wz*XdKXdTIkU*KCRQmu3I-e4A_^#CE~bE8(zk-98Wz#Dh~6T7f+Au+UG9?s zyJB;scb-&+r;$e9yJJg9OD|Q*NJh}EiW%DOSwZ?mN9pGdIx0YzqB-;*6~k^^l&lDj zHqMMQ`j$`HoktHeDZCi8yB%<3?}3W zML3nI)f7`NC&eNmWmK_RVftRW z+QNUS?DgJ81qmVqBm?%^#sJmX;3RWovt`X#RQ+yFlSF2cf3#CMc5O=BTB=Vf| zw`7q(qe3$BloqKfPKie-ga{+jrJRwGt3__4FG5qqZKba=Z7QWbeGUm!9+O2Vb-~45 zRW@cx)Ln+KX(HTeil%ZoPlW9vb)J^W1jVH=&uvYmi0I6r(B^ct+MZnz3N=ku7{Nyh zDIl-uB3t`O5mli5@4i#@wi1UKEH63EePJ z`r2S;XL)6`DypklP6?LJl6{gH)iXmUiGX@;*hLo&rm5VntdKR*=uyYYmRQ6Zr=-^xBw?s+`WR$&c!_aSC13I1F%#QcZ^hHCY697-0`AgH(~7?pDBUi_uk%Wke1 z({yzl2}@lwHxSe)dz1sxPV|n>UT$>7um>5-h}dzJG5ILz6r-{x+cK!05><}6&B}Qh zl`!qa!vkctmB6FiQ}QCW#!bNJ+BCibJgeyVS>Rpk#}QG?vn3f%0cl#N@yg`mXzv^) z;Mm$iclEQE(^IOQ^nQw}G`a?_CN}<9%Oe91AKBOPVDf<@_YK`!a&O~3$-4)>GrYHE z@6eqGzddwE$sH}b2W~%dQ}V_mJ%>7nchv7lb`0DwyuD_7vi;!oL)X<@*S&2ZHQZL; z*4?`2nyxEqHVtp=U!QC_vUcdQBbU}((sFU*MZ>FotM(-7R}M9HH#~7c|M|XiyU%G{ zHhgw+Ny}M#>iW;DIiqD!azTA^LmPm?%%kq#HvXS6_?f&C-+r^fk&zK=8Gx@yTrn2N{>uO@s#P$jYi-?d zbI;l>+f!S6d)UfkZ|b_8yKWZA%FoTU84V*NwQ{9_^y7@BMt%1mW5smysQO$%1~mU@ z5v`CpohfBaLIxAIX*1Z!NZb+>^syO?q&bc-I~>X+D5jM#yE6q{mfVqI^XAFKq_mNd zpS)-Lm_DSFbO;-DA?%|JkOw2PYUyKro6}5biRRW;b#DBh-qrQWX~JkLpCmN>j~3S4)m7=SDcRANvAR}Fkk$1|n668@ysqSw z*LuOWObfF%x;W}LYn642+PSb+td%jlGtExz>S^EEnW>$cHc^HzXPXRdOw&h391T@< zHmZooRznq5hHKSKcgl2Xr#wz=q8+W&3~?jbK15Zz-p@TU092wO_u4I_CUiYQIXE(>dC&=2S|QPt|xe*!y=M zHD1TszX!B1HE(t&C8Y1$eI?$FMW((zpyg{(W_MD^Sk2?SYznEfc?@WA=5U&nB-%!C z;%*ohyZduz!{{sZZXtAAt%4vkME|1&v;r;0>`rR1vAwq=W2?9*_r^9dT??!DIQl+c znV;H2cTrVOZJrf_tS!`vXz8luq_rD%_U+o5(cJpno7>C`HPYETDUa-RueMb7y88v0 zy=1RvNxr1L^M*_<|I(aWd)5*rl}Kl6d4T%0pftkz6JZV18Xr|}Dyr$#`>#p{$-Z476^Kx(Ua+a{^B6OC|^>#ndW?amWE5C*L3!#cHNll$Y6R?&P`u(7IP}&G~>ND!aR9Kh`;|> zm|q_a@qc?X%sZ<>{NsgT{_O)n{^dns{=hpyUUY7lKmBTu&zv9TuRIsz8?FrUKYSkK zx4#_XfBJch|JRQwd?3XC=fN=l&L4u@e`lC~_q`yWJuAe2GZf|-IFs4a z)S2AUL1nVulI0p9UzGcdIfp4Vgce=~PmPel`BF#gk1{x2XIkpj1U2^cUZ3jhZQn{0 z9vO<`+T2^6U=Cdzrd#tNzRG;+Y23qe)zi3pAPI-6qI-ZP^ZN3h)UM7k=0i5--0rg% zGgFatHcu-cn+vU+mS@W5pvzxgrn7lnvZv>!ox9pH^{`jv-sWY@R79w27I9lXR~3@Y zQI~DXW-*8ub&$=TPf&@SJCf}gN0Zm)-r|+aP(!F~+H31utE1G#h>c6^hw5Ug?4IhJ z?49JA#WefY^{Hgr`czL}M{kBoeSOZ&Ub<9vuQqLj@?Pf8h|!~k`w>DtTEvyf_Fpo; zM2(|qNGqIa{^eb5)ShK}wAhh*+b@*1D^-N*UWUg-vt430OrDEI{HWi)35ppcUB0jB zP3>5@b4OQlS9=f5o}_=Q+Ld$Lm(?+sHbQ&deCIg3rkKXrrKWBAiJC{B@A8+IWWF^$ zsGrGvSF^45@wRKK=B8{67ecJ58hTF9N89GZoD@d$G>%^pNt!n@;+UcNmbj7rD5M7) zS9eY335hjqhv}S>G<`T_pNB~p61?YOTmp=+_QxeFgf;)7(R0tBH6QPbWy8)fvL#E* zH!RvrZ6RBsSI}mio%e*i%0*V}VW&`CPm=dDhlT+uMlW|DTzVw>DP(yk*d+m-5U+$v{x z>M}4`aO@0@ZEm)H@i|^Pd6{JSHQpBDuT(|&KO6}2HUAOhYo>?zKfX@m^nays`olC% zKR3kN{wcz1YeW3u=L-32zYX#;e-Y+CUK-+OeK*YCqA~xnpN09`OG5mOScEq{9^ws& zF#pY4L4MiRFdzI~kpIP&F#mWc$hXk=f4DfrJJy9cI~3$kR^O5o>;K<3)KTraTK`|J zJS=rj=uGv04~v0w6GP1k5#66DJaqKmY_l00ck)1V8`; zK)^v@+Er7V#rpqF!&iM(V~$BTi#3tQx&D9JV3v{frPpE&xL6`xLrcot3u3XAfLgC+ zUobO~TM1Oj%oOXz$IdMZkM;j8V<5u%e`*az?~`&Y>;Jo67&tKe ze9iL%Pak};=85|K$;bO2JNW4EBaM%AKV1Ki@9*mGPu@3h@9;e}e{=Aznmdc{XxzQ$ z_Jg+#-`aR<_bmr+_T60nt?rxNym7d%v2RcBn>#@45ajU8JwEzxbaC#%sLJiQ{;s^)=2Cm<|G`1p(Cc(;}OoBnW^22!H?x zfB*=5r3t)tX5^I+eg99JW;+h^SvB6snpVXV=O5rNUh#RN`>rp)mw3n#5*Hu<0w4ea zAOHd&00JNY0w4eaAOHfVGJ$n8$bbB`cRR%U|9OU@YTRFzykLUY;#ajL5 zT6d%m0w4eaAOHd&00JNY0w4eaAn^4i(D?6l$q2pwU+qF*j!En2{eM=wFLk+6z$FNP z00@8p2!H?xfB*=900@8p2!Oz;K;R`>fW9^HL0dk(|6hM9D0CX=ApRc$b8h4`&=)F# z00@8p2!H?xfB*=900@8p2!Mbfu*P`*za||Hy#G%}2L2!b0w4eaAOHd&00JNY0w4ea zAaGg`5byu*Zn_~*NZ1X^`j_# z|6h!c+Oxt}@e;oO&k7U*fdB}A00@8p2!H?xfB*=900^8?1m55F%#m1L1G~`}|NCj* z|7q)fCv}`lf3+EGWTcjv{~N$afEBQy%Y-6EUlOpRewVj?sYSF>Z4$G)=2WU}O>b%k zyD*jNT%Ss|u{s%63LF{v$$N~2Ray^@WbtW&kUU}>j0Dy)hto`fiRRW;bpIkP*Z0J|jF)7!kWuQQYV`zFr*Wj2L` z?p^?VAWQ%^czy$eW}i^sSK7sHDQ)F)-zKdVSrHuSNzdd1)s@A8xh%F1&so))iB+e zdA{yqvj#HzxlQ_^5zQxB6nQ+WPP~7MsA+PQJAyBy&u4w6^OVjsy~XlT?y4hUoP5!; z-nacJ<*R;Of(&na$*@9bE5vQpqz&45KA#OwVZTUBCP)@lGQ(*zwR!A3W?Iy2@swZ{ zR2hQ#JZz*?rCw~1GR#Krm%3iXW@9e`W<027Phn2i+PdN9p0!)Hr?&R?NEI5l_O|cr zl*#A~N`s?Ad4aK%I|Esa6;p(C9ZG=~qY!o{U>I`N=sD;m>O~)kGRu`=m=Yxfjykjg zt&};PO_a<6yEv)7Ns}Ub1i#$kNiB`t!&MvM!)sd;E_+d81O6X%% z(*kV~b2!;k8YER;sb9K#%L^B?W~q=cM5j#&$E_!YSNv>-btOX45oU*}_e`I$rLyK) zou$qE4XNa=t=F@8^JGG*UfCZNUY%F~%c$j)DhY+W2)v$01OifB>yIK}H5Ar8Q2@%c z3TAgU0_#&<9ZBjpG9Y+kViBxlN+)52$-q_#ej1=E5VV;nPE{qC?edqG#9&f-24-iK z{)zFe31zS{iw^YX*=Qt;x7W<6Ogd`pb!RIGMz?9yQ|FaP#;6>QZuA%8M*5?K8huxh zq>K<6e1qL=y0kiE>Pr8d!>;t5Y{)vh(gLlT8BUw4Eo3X~y_C_J8cm)sH~a2X4wbA1 z(C3d(_0M-9&s_Z@TFj&UmqVpheeG>j^P_r#Mh-hhO7CUE!rA^G=SV40&!jqS86PjS z84ZpO;oVF;-2J4)Mvp!AUS6DwEU|cqP-d%Rp=bYmT%xi=@5;~|Tt4zbm@kZm_Rj_K|Rl~{@=nfuIv9rvSN_v+DOP(ukS=KiN=yy9<-6rbmnx9jf4`(-sF~K zPij+YSC4ZyA=)#;dYbT^DW1#Sud>yXx~DE$u~uPit|T{Eatqs(?C7HgM{K>Yu2F5S zVc&YeS9k1NFBEG_nax$a7~uPNhxnZD)0+MXT>t;s+vk-{qVNAZWIkGZfK+6kcb-_& zd8)k0Rr=}Vj+g&5`u=~s55;7>(?xn900JNY0w4eaAOHd&00JNY0wACWRD5*xhvoGC z|0ZMnFW&$A>WsnvQq4UTBK8D!`MEX*u3y~5^a&Fs0>2;t0w4eaAOHd&00JNY0w4ea zAOHd;zY|EO#eJ-d zu_^3+W5!?t^@S)9009sH0T2KI5C8!X009sH0T2LzV<$dA@A8i!x|Ko$!MapZMhf@=0T2KI5C8!X009sH0T2KI5C8!XI8_MHC;akwd3U{h|1Z}1 zi=#^a!Cw#n0T2KI5C8!X009sH0T2KI5CDO%00F$T{|aOxOaK88009sH0T2KI5C8!X k009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0fWH*17a;@LI3~& diff --git a/Application/Entities.cs b/Application/Entities.cs index ad7ebca..6278bfd 100644 --- a/Application/Entities.cs +++ b/Application/Entities.cs @@ -1,139 +1,96 @@ -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Data.Entity.Infrastructure; +using Dapper; +using FeedCenter.Data; +using FeedCenter.Options; +using Realms; +using System; +using System.Data.SqlServerCe; +using System.IO; using System.Linq; namespace FeedCenter { - public partial class FeedCenterEntities + public class FeedCenterEntities { - #region Dispose + public Realm Realm { get; private set; } - protected override void Dispose(bool disposing) + public RealmObservableCollection Categories { get; private set; } + public RealmObservableCollection Feeds { get; private set; } + public RealmObservableCollection Settings { get; private set; } + + public FeedCenterEntities() { - if (disposing) - { - var manager = ((IObjectContextAdapter) this).ObjectContext.ObjectStateManager; - manager.ObjectStateManagerChanged -= HandleObjectStateManagerObjectStateManagerChanged; - _hookedStateManager = false; - } - - base.Dispose(disposing); + Load(); } - #endregion - - private bool _hookedStateManager; - - #region All categories - - private ObservableCollection _allCategories; - - public ObservableCollection AllCategories + public void Refresh() { - get + Realm.Refresh(); + } + + public void Load() + { + var realmConfiguration = new RealmConfiguration($"{Database.DatabasePath}/FeedCenter.realm"); + + Realm = Realm.GetInstance(realmConfiguration); + + if (File.Exists(Database.DatabaseFile)) { - if (_allCategories == null) + using var connection = new SqlCeConnection($"Data Source={Database.DatabaseFile}"); + + connection.Open(); + + var settings = connection.Query("SELECT * FROM Setting").OrderBy(s => s.Version).ToList(); + var categories = connection.Query("SELECT * FROM Category").ToList(); + var feeds = connection.Query("SELECT * FROM Feed").ToList(); + var feedItems = connection.Query("SELECT * FROM FeedItem").ToList(); + + Realm.Write(() => { - _allCategories = new ObservableCollection(Categories); - - if (!_hookedStateManager) + foreach (var category in categories) { - var manager = ((IObjectContextAdapter) this).ObjectContext.ObjectStateManager; - manager.ObjectStateManagerChanged += HandleObjectStateManagerObjectStateManagerChanged; - _hookedStateManager = true; + category.Feeds = feeds.Where(f => f.CategoryId == category.Id).ToList(); } - } - return _allCategories; + foreach (var feed in feeds) + { + feed.Category = categories.FirstOrDefault(c => c.Id == feed.CategoryId); + } + + foreach (var feedItem in feedItems) + { + var feed = feeds.First(f => f.Id == feedItem.FeedId); + + feed.Items.Add(feedItem); + } + + Realm.Add(feeds); + Realm.Add(categories); + Realm.Add(settings, true); + }); + + connection.Close(); + + File.Move(Database.DatabaseFile, Database.DatabaseFile + "_bak"); } + + Settings = new RealmObservableCollection(Realm); + Feeds = new RealmObservableCollection(Realm); + Categories = new RealmObservableCollection(Realm); + + if (!Categories.Any()) + { + Realm.Write(() => Categories.Add(Category.CreateDefault())); + } + } + + public void SaveChanges(Action action) + { + Realm.Write(action); } public Category DefaultCategory { - get { return AllCategories.First(c => c.IsDefault); } + get { return Categories.First(c => c.IsDefault); } } - - #endregion - - #region All feeds - - private ObservableCollection _allFeeds; - - public ObservableCollection AllFeeds - { - get - { - if (_allFeeds == null) - { - _allFeeds = new ObservableCollection(Feeds); - - if (!_hookedStateManager) - { - var manager = ((IObjectContextAdapter) this).ObjectContext.ObjectStateManager; - manager.ObjectStateManagerChanged += HandleObjectStateManagerObjectStateManagerChanged; - _hookedStateManager = true; - } - } - - return _allFeeds; - } - } - - #endregion - - #region Object state manager - - void HandleObjectStateManagerObjectStateManagerChanged(object sender, CollectionChangeEventArgs e) - { - var element = e.Element as Category; - - if (element != null) - { - if (_allCategories == null) - return; - - var category = element; - - switch (e.Action) - { - case CollectionChangeAction.Add: - _allCategories.Add(category); - break; - case CollectionChangeAction.Remove: - _allCategories.Remove(category); - break; - case CollectionChangeAction.Refresh: - _allCategories.Clear(); - foreach (var loopCategory in Categories) - _allCategories.Add(loopCategory); - break; - } - } - else if (e.Element is Feed) - { - if (_allFeeds == null) - return; - - var feed = (Feed) e.Element; - - switch (e.Action) - { - case CollectionChangeAction.Add: - _allFeeds.Add(feed); - break; - case CollectionChangeAction.Remove: - _allFeeds.Remove(feed); - break; - case CollectionChangeAction.Refresh: - _allFeeds.Clear(); - foreach (var loopfeed in Feeds) - _allFeeds.Add(loopfeed); - break; - } - } - } - - #endregion } -} +} \ No newline at end of file diff --git a/Application/Feed.cs b/Application/Feed.cs deleted file mode 100644 index 6b58466..0000000 --- a/Application/Feed.cs +++ /dev/null @@ -1,59 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FeedCenter -{ - using System; - using System.Collections.Generic; - - public partial class Feed - { - public Feed() - { - this.Name = ""; - this.Title = ""; - this.Source = ""; - this.Link = ""; - this.Description = ""; - this.LastChecked = new DateTime(599266080000000000, DateTimeKind.Unspecified); - this.CheckInterval = 60; - this.Enabled = true; - this.Authenticate = false; - this.Username = ""; - this.Password = ""; - this.Domain = ""; - this.LastUpdated = new DateTime(599266080000000000, DateTimeKind.Unspecified); - this.Actions = new HashSet(); - this.Items = new HashSet(); - } - - public System.Guid ID { get; set; } - public string Name { get; set; } - public string Title { get; set; } - public string Source { get; set; } - public string Link { get; set; } - public string Description { get; set; } - public System.DateTime LastChecked { get; set; } - public int CheckInterval { get; set; } - public bool Enabled { get; set; } - public bool Authenticate { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public string Domain { get; set; } - public FeedCenter.FeedReadResult LastReadResult { get; set; } - public System.DateTime LastUpdated { get; set; } - public FeedCenter.FeedItemComparison ItemComparison { get; set; } - private System.Guid CategoryID { get; set; } - public FeedCenter.MultipleOpenAction MultipleOpenAction { get; set; } - - public virtual Category Category { get; set; } - public virtual ICollection Actions { get; set; } - public virtual ICollection Items { get; set; } - } -} diff --git a/Application/FeedAction.cs b/Application/FeedAction.cs deleted file mode 100644 index d853061..0000000 --- a/Application/FeedAction.cs +++ /dev/null @@ -1,26 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FeedCenter -{ - using System; - using System.Collections.Generic; - - public partial class FeedAction - { - public System.Guid ID { get; set; } - public System.Guid FeedID { get; set; } - public int Field { get; set; } - public string Search { get; set; } - public string Replace { get; set; } - public int Sequence { get; set; } - - public virtual Feed Feed { get; set; } - } -} diff --git a/Application/FeedCenter.csproj b/Application/FeedCenter.csproj index cfb4152..7e65192 100644 --- a/Application/FeedCenter.csproj +++ b/Application/FeedCenter.csproj @@ -1,30 +1,13 @@ - - + - Debug + net70-windows x86 - 8.0.30703 - 2.0 - {BD3D12F2-DE23-4466-83B1-1EB617A877A4} WinExe - Properties - FeedCenter - FeedCenter - v4.5.1 - - - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 false - - - - - - - - + + + + \\server\d\FeedCenter\ true Unc @@ -45,38 +28,19 @@ false true true - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false + false + true + true + true - - + + + false + - false - - - - + Resources\Application.ico @@ -91,322 +55,40 @@ Properties\app.manifest - true - bin\Debug\ - DEBUG;TRACE - full - AnyCPU bin\Debug\FeedCenter.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt MinimumRecommendedRules.ruleset ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets false ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules false - false true - false - bin\Release\ - TRACE - true - pdbonly - AnyCPU bin\Release\FeedCenter.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt MinimumRecommendedRules.ruleset ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - true bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt MinimumRecommendedRules.ruleset false false bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt MinimumRecommendedRules.ruleset - - False - ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.dll - - - ..\packages\EntityFramework.6.1.1\lib\net45\EntityFramework.SqlServer.dll - - - ..\packages\EntityFramework.SqlServerCompact.6.1.1\lib\net45\EntityFramework.SqlServerCompact.dll - - - ..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll - True - - - ..\packages\NameBasedGrid.0.10.1\lib\net40\NameBasedGrid.dll - - - - - - - True - ..\packages\Microsoft.SqlServer.Compact.4.0.8854.1\lib\net40\System.Data.SqlServerCe.dll - - - True - ..\packages\Microsoft.SqlServer.Compact.4.0.8854.1\lib\net40\System.Data.SqlServerCe.Entity.dll - - - - - - - - 4.0 - - - - - - - - - FeedChooserWindow.xaml - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - - Model.tt - - - - - Model.tt - - - Model.tt - - - FeedErrorWindow.xaml - - - Model.tt - - - - True - True - Model.Context.tt - - - True - True - Model.tt - - - True - True - Model.edmx - - - - AboutOptionsPanel.xaml - - - BulkFeedWindow.xaml - - - CategoryWindow.xaml - - - DisplayOptionsPanel.xaml - - - FeedsOptionsPanel.xaml - - - FeedWindow.xaml - - - GeneralOptionsPanel.xaml - - - - - OptionsWindow.xaml - - - UpdateOptionsPanel.xaml - - - Model.tt - - - - SplashWindow.xaml - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - - - - - - - - - MainWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - Code - - - True - True - Resources.resx - - - True - Settings.settings - True - - - PublicResXFileCodeGenerator - Resources.Designer.cs - Designer - - - Designer - EntityModelCodeGenerator Model.Designer.cs - - TextTemplatingFileGenerator - Model.Context.cs - Model.edmx - - - TextTemplatingFileGenerator - Model.cs - Model.edmx - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - - - - - - False @@ -442,32 +124,29 @@ - - {ed1c07a1-54f5-4796-8b06-2a0bb1960d84} - Common.Native - - - {0074c983-550e-4094-9e8c-f566fb669297} - Common.Wpf - - - {17864d82-457d-4a0a-bc10-1d07f2b3a5d6} - Common - + + + + + + + + + + + + + + + + - - if not exist "$(TargetDir)x86" md "$(TargetDir)x86" - xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8854.1\NativeBinaries\x86\*.*" "$(TargetDir)x86" - if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" - xcopy /s /y "$(SolutionDir)packages\Microsoft.SqlServer.Compact.4.0.8854.1\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" + if not exist "$(TargetDir)x86" md "$(TargetDir)x86" + xcopy /s /y "$(PkgMicrosoft_SqlServer_Compact)\NativeBinaries\x86\*.*" "$(TargetDir)x86" + if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" + xcopy /s /y "$(PkgMicrosoft_SqlServer_Compact)\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" + - \ No newline at end of file diff --git a/Application/FeedCenterEntities.datasource b/Application/FeedCenterEntities.datasource deleted file mode 100644 index c919ef6..0000000 --- a/Application/FeedCenterEntities.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - FeedCenter.FeedCenterEntities, Model.Designer.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Application/FeedCenterEntities1.datasource b/Application/FeedCenterEntities1.datasource deleted file mode 100644 index c919ef6..0000000 --- a/Application/FeedCenterEntities1.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - FeedCenter.FeedCenterEntities, Model.Designer.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Application/FeedCenterEntities2.datasource b/Application/FeedCenterEntities2.datasource deleted file mode 100644 index c919ef6..0000000 --- a/Application/FeedCenterEntities2.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - FeedCenter.FeedCenterEntities, Model.Designer.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/Application/FeedErrorWindow.xaml.cs b/Application/FeedErrorWindow.xaml.cs index 048ea1f..bc72b7c 100644 --- a/Application/FeedErrorWindow.xaml.cs +++ b/Application/FeedErrorWindow.xaml.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Windows; using System.Windows.Data; using System.Windows.Input; +using FeedCenter.Data; namespace FeedCenter { @@ -18,10 +19,10 @@ namespace FeedCenter public bool? Display(Window owner) { - _database = new FeedCenterEntities(); + _database = Database.Entities; // Create a view and sort it by name - _collectionViewSource = new CollectionViewSource { Source = _database.AllFeeds }; + _collectionViewSource = new CollectionViewSource { Source = _database.Feeds }; _collectionViewSource.Filter += HandleCollectionViewSourceFilter; _collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); @@ -98,7 +99,7 @@ namespace FeedCenter private void HandleOkayButtonClick(object sender, RoutedEventArgs e) { // Save the actual settings - _database.SaveChanges(); + _database.SaveChanges(() => { }); DialogResult = true; diff --git a/Application/FeedItem.cs b/Application/FeedItem.cs deleted file mode 100644 index b7e3dee..0000000 --- a/Application/FeedItem.cs +++ /dev/null @@ -1,38 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FeedCenter -{ - using System; - using System.Collections.Generic; - - public partial class FeedItem - { - public FeedItem() - { - this.Title = ""; - this.Link = ""; - this.Description = ""; - this.LastFound = new DateTime(599266080000000000, DateTimeKind.Unspecified); - } - - public System.Guid ID { get; set; } - public System.Guid FeedID { get; set; } - public string Title { get; set; } - public string Link { get; set; } - public string Description { get; set; } - public bool BeenRead { get; set; } - public System.DateTime LastFound { get; set; } - public bool New { get; set; } - public string Guid { get; set; } - public int Sequence { get; set; } - - public virtual Feed Feed { get; set; } - } -} diff --git a/Application/FeedParsers/FeedParserBase.cs b/Application/FeedParsers/FeedParserBase.cs index 86b7583..201c168 100644 --- a/Application/FeedParsers/FeedParserBase.cs +++ b/Application/FeedParsers/FeedParserBase.cs @@ -40,7 +40,7 @@ namespace FeedCenter.FeedParsers protected void HandleFeedItem(XmlNode node, ref int sequence) { // Build a feed item from the node - FeedItem newFeedItem = ParseFeedItem(node); + var newFeedItem = ParseFeedItem(node); if (newFeedItem == null) return; @@ -50,7 +50,7 @@ namespace FeedCenter.FeedParsers return; // Look for an item that has the same guid - FeedItem existingFeedItem = Feed.Items.FirstOrDefault(item => item.Guid == newFeedItem.Guid && item.ID != newFeedItem.ID); + var existingFeedItem = Feed.Items.FirstOrDefault(item => item.Guid == newFeedItem.Guid && item.Id != newFeedItem.Id); // Check to see if we already have this feed item if (existingFeedItem == null) @@ -102,7 +102,7 @@ namespace FeedCenter.FeedParsers public static FeedParserBase CreateFeedParser(Feed feed, string feedText) { - FeedType feedType = DetectFeedType(feedText); + var feedType = DetectFeedType(feedText); switch (feedType) { diff --git a/Application/FeedParsers/RdfParser.cs b/Application/FeedParsers/RdfParser.cs index ba01901..8289f53 100644 --- a/Application/FeedParsers/RdfParser.cs +++ b/Application/FeedParsers/RdfParser.cs @@ -19,7 +19,7 @@ namespace FeedCenter.FeedParsers document.LoadXml(feedText); // Create the namespace manager - XmlNamespaceManager namespaceManager = document.GetAllNamespaces(); + var namespaceManager = document.GetAllNamespaces(); // Get the root node XmlNode rootNode = document.DocumentElement; @@ -29,7 +29,7 @@ namespace FeedCenter.FeedParsers return FeedReadResult.UnknownError; // Get the channel node - XmlNode channelNode = rootNode.SelectSingleNode("default:channel", namespaceManager); + var channelNode = rootNode.SelectSingleNode("default:channel", namespaceManager); if (channelNode == null) return FeedReadResult.InvalidXml; @@ -55,7 +55,7 @@ namespace FeedCenter.FeedParsers } // Initialize the sequence number for items - int sequence = 0; + var sequence = 0; // Loop over all nodes in the channel node foreach (XmlNode node in rootNode.ChildNodes) @@ -82,7 +82,7 @@ namespace FeedCenter.FeedParsers protected override FeedItem ParseFeedItem(XmlNode node) { // Create a new feed item - FeedItem feedItem = FeedItem.Create(); + var feedItem = FeedItem.Create(); // Loop over all nodes in the feed node foreach (XmlNode childNode in node.ChildNodes) diff --git a/Application/FeedParsers/RssParser.cs b/Application/FeedParsers/RssParser.cs index be3148d..fe414c9 100644 --- a/Application/FeedParsers/RssParser.cs +++ b/Application/FeedParsers/RssParser.cs @@ -20,7 +20,7 @@ namespace FeedCenter.FeedParsers document.LoadXml(feedText); // Create the namespace manager - XmlNamespaceManager namespaceManager = document.GetAllNamespaces(); + var namespaceManager = document.GetAllNamespaces(); // Get the root node XmlNode rootNode = document.DocumentElement; @@ -37,7 +37,7 @@ namespace FeedCenter.FeedParsers return FeedReadResult.InvalidXml; // Initialize the sequence number for items - int sequence = 0; + var sequence = 0; // Loop over all nodes in the channel node foreach (XmlNode node in channelNode.ChildNodes) @@ -76,7 +76,7 @@ namespace FeedCenter.FeedParsers protected override FeedItem ParseFeedItem(XmlNode node) { // Create a new feed item - FeedItem feedItem = FeedItem.Create(); + var feedItem = FeedItem.Create(); // Loop over all nodes in the feed node foreach (XmlNode childNode in node.ChildNodes) @@ -95,7 +95,7 @@ namespace FeedCenter.FeedParsers case "guid": feedItem.Guid = childNode.InnerText.Trim(); - bool permaLink = true; + var permaLink = true; if (childNode.Attributes != null) { diff --git a/Application/Feeds/Category.cs b/Application/Feeds/Category.cs index 90f0cfc..50e8b5d 100644 --- a/Application/Feeds/Category.cs +++ b/Application/Feeds/Category.cs @@ -1,15 +1,31 @@ using System; +using System.Collections.Generic; +using Realms; namespace FeedCenter { - public partial class Category + public class Category : RealmObject { + private const string DefaultCategoryName = "< default >"; + + [PrimaryKey] + [MapTo("ID")] + public Guid Id { get; set; } + public string Name { get; set; } + + [Ignored] + public ICollection Feeds { get; set; } + public static Category Create() { - return new Category { ID = Guid.NewGuid() }; + return new Category { Id = Guid.NewGuid() }; + } + public static Category CreateDefault() + { + return new Category { Id = Guid.NewGuid(), Name = DefaultCategoryName }; } - public bool IsDefault => Name == "< default >"; + public bool IsDefault => Name == DefaultCategoryName; // ReSharper disable once UnusedMember.Global public int SortKey => IsDefault ? 0 : 1; diff --git a/Application/Feeds/Feed.cs b/Application/Feeds/Feed.cs index e9634cb..96e7e75 100644 --- a/Application/Feeds/Feed.cs +++ b/Application/Feeds/Feed.cs @@ -1,17 +1,21 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Common.Debug; +using Common.Debug; using Common.Update; using Common.Xml; using FeedCenter.Data; using FeedCenter.FeedParsers; using FeedCenter.Properties; +using Realms; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; namespace FeedCenter { @@ -55,8 +59,57 @@ namespace FeedCenter #endregion - public partial class Feed + public class Feed : RealmObject { + [PrimaryKey] + [MapTo("ID")] + public Guid Id { get; set; } + public string Name { get; set; } + public string Title { get; set; } + public string Source { get; set; } + public string Link { get; set; } + public string Description { get; set; } + public DateTimeOffset LastChecked { get; set; } + public int CheckInterval { get; set; } + public bool Enabled { get; set; } + public bool Authenticate { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string Domain { get; set; } + + private string LastReadResultRaw { get; set; } + + public FeedReadResult LastReadResult + { + get => Enum.TryParse(LastReadResultRaw, out FeedReadResult result) ? result : FeedReadResult.Success; + set => LastReadResultRaw = value.ToString(); + } + + public DateTimeOffset LastUpdated { get; set; } + + private string ItemComparisonRaw { get; set; } + + public FeedItemComparison ItemComparison + { + get => Enum.TryParse(ItemComparisonRaw, out FeedItemComparison result) ? result : FeedItemComparison.Default; + set => ItemComparisonRaw = value.ToString(); + } + + [MapTo("CategoryID")] + public Guid CategoryId { get; set; } + + private string MultipleOpenActionRaw { get; set; } + + public MultipleOpenAction MultipleOpenAction + { + get => Enum.TryParse(MultipleOpenActionRaw, out MultipleOpenAction result) ? result : MultipleOpenAction.IndividualPages; + set => MultipleOpenActionRaw = value.ToString(); + } + + public Category Category { get; set; } + + public IList Items { get; } + // ReSharper disable once UnusedMember.Global public string LastReadResultDescription { @@ -66,7 +119,7 @@ namespace FeedCenter var lastReadResult = LastReadResult; // Build the name of the resource using the enum name and the value - var resourceName = $"{typeof(FeedReadResult).Name}_{lastReadResult}"; + var resourceName = $"{nameof(FeedReadResult)}_{lastReadResult}"; // Try to get the value from the resources var resourceValue = Resources.ResourceManager.GetString(resourceName); @@ -76,9 +129,11 @@ namespace FeedCenter } } + private static HttpClient _httpClient; + public static Feed Create(FeedCenterEntities database) { - return new Feed { ID = Guid.NewGuid(), CategoryID = database.DefaultCategory.ID }; + return new Feed { Id = Guid.NewGuid(), CategoryId = database.DefaultCategory.Id }; } #region Reading @@ -109,7 +164,7 @@ namespace FeedCenter // If the feed was successfully read and we have no last update timestamp - set the last update timestamp to now if (result == FeedReadResult.Success && LastUpdated == Extensions.SqlDateTimeZero.Value) - LastUpdated = DateTime.Now; + LastUpdated = DateTimeOffset.Now; Tracer.DecrementIndentLevel(); Tracer.WriteLine("Done reading feed: {0}", result); @@ -138,74 +193,46 @@ namespace FeedCenter { try { - // Add extra security protocols - ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; - - // Create the web request - var request = WebRequest.Create(new Uri(Source)); - - // If this is an http request set some special properties - if (request is HttpWebRequest webRequest) + // Create and configure the HTTP client if needed + if (_httpClient == null) { - // Make sure to use HTTP version 1.1 - webRequest.ProtocolVersion = HttpVersion.Version11; - - // Set that we'll accept compressed data - webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; - - // Set a timeout - webRequest.Timeout = 10000; - - // Make sure the service point closes the connection right away - webRequest.ServicePoint.ConnectionLeaseTimeout = 0; - - // If we need to authenticate then set the credentials - if (Authenticate) - webRequest.Credentials = new NetworkCredential(Username, Password, Domain); + _httpClient = new HttpClient(new HttpClientHandler + { + // Set that we'll accept compressed data + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }); // Set a user agent string - if (string.IsNullOrWhiteSpace(Settings.Default.DefaultUserAgent)) - webRequest.UserAgent = "FeedCenter/" + UpdateCheck.LocalVersion; - else - webRequest.UserAgent = Settings.Default.DefaultUserAgent; + var userAgent = string.IsNullOrWhiteSpace(Settings.Default.DefaultUserAgent) ? "FeedCenter/" + UpdateCheck.LocalVersion : Settings.Default.DefaultUserAgent; + _httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(userAgent); + + // Set a timeout + _httpClient.Timeout = TimeSpan.FromSeconds(10); } - // Set the default encoding - var encoding = Encoding.UTF8; + // If we need to authenticate then set the credentials + _httpClient.DefaultRequestHeaders.Authorization = Authenticate ? new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Username}:{Password}"))) : null; // Attempt to get the response - using (var response = (HttpWebResponse) request.GetResponse()) - { - // If the response included an encoding then change the encoding - if (response.ContentEncoding.Length > 0) - encoding = Encoding.GetEncoding(response.ContentEncoding); + var feedStream = _httpClient.GetStreamAsync(Source).Result; - // Get the response stream - using (var responseStream = response.GetResponseStream()) - { - if (responseStream == null) - return Tuple.Create(FeedReadResult.NoResponse, string.Empty); + // Create the text reader + using StreamReader textReader = new XmlSanitizingStream(feedStream, Encoding.UTF8); - // Create the text reader - using (StreamReader textReader = new XmlSanitizingStream(responseStream, encoding)) - { - // Get the feed text - var feedText = textReader.ReadToEnd(); + // Get the feed text + var feedText = textReader.ReadToEnd(); - // Get rid of any leading and trailing whitespace - feedText = feedText.Trim(); + // Get rid of any leading and trailing whitespace + feedText = feedText.Trim(); - // Clean up common invalid XML characters - feedText = feedText.Replace(" ", " "); + // Clean up common invalid XML characters + feedText = feedText.Replace(" ", " "); - // Find ampersands that aren't properly escaped and replace them with escaped versions - var r = new Regex("&(?!(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);)"); - feedText = r.Replace(feedText, "&"); + // Find ampersands that aren't properly escaped and replace them with escaped versions + var r = new Regex("&(?!(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);)"); + feedText = r.Replace(feedText, "&"); - return Tuple.Create(FeedReadResult.Success, feedText); - } - } - } + return Tuple.Create(FeedReadResult.Success, feedText); } catch (IOException ioException) { @@ -281,7 +308,7 @@ namespace FeedCenter if (!forceRead) { // Figure out how long since we last checked - var timeSpan = DateTime.Now - LastChecked; + var timeSpan = DateTimeOffset.Now - LastChecked; // Check if we are due to read the feed if (timeSpan.TotalMinutes < CheckInterval) @@ -289,7 +316,7 @@ namespace FeedCenter } // We're checking it now so update the time - LastChecked = DateTime.Now; + LastChecked = DateTimeOffset.Now; // Read the feed text var retrieveResult = RetrieveFeed(); @@ -322,16 +349,10 @@ namespace FeedCenter // Loop over the items to be removed foreach (var itemToRemove in removedItems) { - // Delete the item from the database - database.FeedItems.Remove(itemToRemove); - // Remove the item from the list Items.Remove(itemToRemove); } - // Process actions on this feed - ProcessActions(); - return FeedReadResult.Success; } catch (InvalidFeedFormatException exception) @@ -348,22 +369,6 @@ namespace FeedCenter } } - private void ProcessActions() - { - var sortedActions = from action in Actions orderby action.Sequence select action; - - foreach (var feedAction in sortedActions) - { - switch (feedAction.Field) - { - case 0: - Title = Title.Replace(feedAction.Search, feedAction.Replace); - - break; - } - } - } - #endregion } } \ No newline at end of file diff --git a/Application/Feeds/FeedAction.cs b/Application/Feeds/FeedAction.cs deleted file mode 100644 index db13357..0000000 --- a/Application/Feeds/FeedAction.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace FeedCenter -{ - public partial class FeedAction - { - #region Constructor - - public FeedAction() - { - ID = Guid.NewGuid(); - } - - #endregion - - #region Methods - - public override string ToString() - { - return string.Format(Properties.Resources.FeedActionDescription, Field, Search, Replace); - } - - #endregion - } -} diff --git a/Application/Feeds/FeedItem.cs b/Application/Feeds/FeedItem.cs index 6c4ed69..7f4c5d3 100644 --- a/Application/Feeds/FeedItem.cs +++ b/Application/Feeds/FeedItem.cs @@ -1,20 +1,40 @@ using System; using System.Text.RegularExpressions; +using FeedCenter.Options; +using Realms; namespace FeedCenter { - public partial class FeedItem + public class FeedItem : RealmObject { + [PrimaryKey] + [MapTo("ID")] + public Guid Id { get; set; } + + [MapTo("FeedID")] + public Guid FeedId { get; set; } + + public string Title { get; set; } + public string Link { get; set; } + public string Description { get; set; } + public bool BeenRead { get; set; } + public DateTimeOffset LastFound { get; set; } + public bool New { get; set; } + public string Guid { get; set; } + public int Sequence { get; set; } + + public Feed Feed { get; set; } + public static FeedItem Create() { - return new FeedItem { ID = System.Guid.NewGuid() }; + return new FeedItem { Id = System.Guid.NewGuid() }; } #region Methods public override string ToString() { - string title = Title; + var title = Title; switch (Properties.Settings.Default.MultipleLineDisplay) { @@ -28,13 +48,17 @@ namespace FeedCenter case Options.MultipleLineDisplay.FirstLine: // Find the first newline - int newlineIndex = title.IndexOf("\n", StringComparison.Ordinal); + var newlineIndex = title.IndexOf("\n", StringComparison.Ordinal); // If a newline was found return everything before it if (newlineIndex > -1) - title = title.Substring(0, newlineIndex); + title = title[..newlineIndex]; break; + case MultipleLineDisplay.Normal: + break; + default: + throw new ArgumentOutOfRangeException(); } // Condense multiple spaces to one space diff --git a/Application/FodyWeavers.xml b/Application/FodyWeavers.xml new file mode 100644 index 0000000..cc07b89 --- /dev/null +++ b/Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Application/FodyWeavers.xsd b/Application/FodyWeavers.xsd new file mode 100644 index 0000000..fa5cb18 --- /dev/null +++ b/Application/FodyWeavers.xsd @@ -0,0 +1,34 @@ + + + + + + + + + + + Disables anonymized usage information from being sent on build. Read more about what data is being collected and why here: https://github.com/realm/realm-dotnet/blob/main/Realm/Realm.Weaver/Analytics.cs + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/Application/MainWindow/CategoryList.cs b/Application/MainWindow/CategoryList.cs index ef2796b..96ec954 100644 --- a/Application/MainWindow/CategoryList.cs +++ b/Application/MainWindow/CategoryList.cs @@ -6,7 +6,7 @@ using FeedCenter.Properties; namespace FeedCenter { - public partial class MainWindow + public partial class MainWindow : IDisposable { private void DisplayCategory() { @@ -44,7 +44,7 @@ namespace FeedCenter Tag = category, // Set the current item to bold - FontWeight = category.ID == _currentCategory?.ID ? FontWeights.Bold : FontWeights.Normal + FontWeight = category.Id == _currentCategory?.Id ? FontWeights.Bold : FontWeights.Normal }; // Handle the click @@ -70,7 +70,7 @@ namespace FeedCenter var category = (Category) menuItem.Tag; // If the category changed then reset the current feed to the first in the category - if (_currentCategory?.ID != category?.ID) + if (_currentCategory?.Id != category?.Id) { _currentFeed = category == null ? _database.Feeds.FirstOrDefault() : category.Feeds.FirstOrDefault(); } @@ -79,9 +79,9 @@ namespace FeedCenter _currentCategory = category; // Get the current feed list to match the category - _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.ID == _currentCategory.ID); + _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.Id == _currentCategory.Id); - // Reset the feed index + // Refresh the feed index _feedIndex = -1; // Get the first feed @@ -94,7 +94,14 @@ namespace FeedCenter DisplayCategory(); DisplayFeed(); - Settings.Default.LastCategoryID = _currentCategory?.ID.ToString() ?? string.Empty; + Settings.Default.LastCategoryID = _currentCategory?.Id.ToString() ?? string.Empty; + } + + public void Dispose() + { + _mainTimer?.Dispose(); + _feedReadWorker?.Dispose(); + _commandLineListener?.Dispose(); } } } diff --git a/Application/MainWindow/DragDrop.cs b/Application/MainWindow/DragDrop.cs index e628440..17eadd3 100644 --- a/Application/MainWindow/DragDrop.cs +++ b/Application/MainWindow/DragDrop.cs @@ -35,13 +35,16 @@ namespace FeedCenter // Get the data as a string var data = (string) e.Data.GetData(DataFormats.Text); + if (string.IsNullOrEmpty(data)) + return; + // Check to see if the data starts with any known Chrome extension - var chromeExtension = _chromeExtensions.FirstOrDefault(c => data.StartsWith(c)); + var chromeExtension = _chromeExtensions.FirstOrDefault(data.StartsWith); // Remove the Chrome extension URL and decode the URL if (chromeExtension != null) { - data = data.Substring(chromeExtension.Length); + data = data[chromeExtension.Length..]; data = WebUtility.UrlDecode(data); } diff --git a/Application/MainWindow/FeedCreation.cs b/Application/MainWindow/FeedCreation.cs index 00dc559..75e973f 100644 --- a/Application/MainWindow/FeedCreation.cs +++ b/Application/MainWindow/FeedCreation.cs @@ -64,10 +64,7 @@ namespace FeedCenter feed.Name = feed.Title; // Add the feed to the feed table - _database.Feeds.Add(feed); - - // Save the changes - _database.SaveChanges(); + _database.SaveChanges(() => _database.Feeds.Add(feed)); // Show a tip NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info); @@ -77,7 +74,7 @@ namespace FeedCenter } else { - // Feed read failed - ceate a new feed window + // Feed read failed - create a new feed window var feedForm = new FeedWindow(); var dialogResult = feedForm.Display(_database, feed, this); @@ -86,10 +83,7 @@ namespace FeedCenter if (dialogResult.HasValue && dialogResult.Value) { // Add the feed to the feed table - _database.Feeds.Add(feed); - - // Save the changes - _database.SaveChanges(); + _database.SaveChanges(() => _database.Feeds.Add(feed)); // Re-initialize the feed display DisplayFeed(); diff --git a/Application/MainWindow/FeedList.cs b/Application/MainWindow/FeedList.cs index 11e906f..5f3ce9f 100644 --- a/Application/MainWindow/FeedList.cs +++ b/Application/MainWindow/FeedList.cs @@ -34,15 +34,14 @@ namespace FeedCenter var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext; // The feed item has been read and is no longer new - feedItem.BeenRead = true; - feedItem.New = false; + _database.SaveChanges(() => + { + feedItem.BeenRead = true; + feedItem.New = false; + }); // Remove the item from the list LinkTextList.Items.Remove(feedItem); - - // Save the changes - _database.SaveChanges(); - } private void HandleItemMouseDoubleClick(object sender, MouseButtonEventArgs e) @@ -54,14 +53,14 @@ namespace FeedCenter if (BrowserCommon.OpenLink(feedItem.Link)) { // The feed item has been read and is no longer new - feedItem.BeenRead = true; - feedItem.New = false; + _database.SaveChanges(() => + { + feedItem.BeenRead = true; + feedItem.New = false; + }); // Remove the item from the list LinkTextList.Items.Remove(feedItem); - - // Save the changes - _database.SaveChanges(); } } @@ -83,10 +82,9 @@ namespace FeedCenter Tag = feed, // Set the current item to bold - FontWeight = feed == _currentFeed ? FontWeights.Bold : FontWeights.Normal + FontWeight = feed.Id == _currentFeed.Id ? FontWeights.Bold : FontWeights.Normal }; - // Handle the click menuItem.Click += HandleFeedMenuItemClick; @@ -113,7 +111,7 @@ namespace FeedCenter var feedIndex = 0; foreach (var loopFeed in _feedList.OrderBy(loopFeed => loopFeed.Name)) { - if (loopFeed == feed) + if (loopFeed.Id == feed.Id) { _feedIndex = feedIndex; break; diff --git a/Application/MainWindow/FeedReading.cs b/Application/MainWindow/FeedReading.cs index e47c7aa..53ba953 100644 --- a/Application/MainWindow/FeedReading.cs +++ b/Application/MainWindow/FeedReading.cs @@ -21,7 +21,7 @@ namespace FeedCenter private void SetProgressMode(bool value, int feedCount) { - // Reset the progress bar if we need it + // Refresh the progress bar if we need it if (value) { FeedReadProgress.Value = 0; @@ -65,7 +65,7 @@ namespace FeedCenter return; // Switch to progress mode - SetProgressMode(true, _database.Feeds.Count()); + SetProgressMode(true, _database.Feeds.Count); // Create the input class var workerInput = new FeedReadWorkerInput { ForceRead = forceRead, Feed = null }; @@ -82,7 +82,7 @@ namespace FeedCenter private void HandleFeedReadWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { - // Reset the database to current settings + // Refresh the database to current settings ResetDatabase(); // Save settings @@ -123,10 +123,10 @@ namespace FeedCenter var database = new FeedCenterEntities(); // Get the worker - var worker = (BackgroundWorker) sender; + var worker = (BackgroundWorker)sender; // Get the input information - var workerInput = (FeedReadWorkerInput) e.Argument; + var workerInput = (FeedReadWorkerInput)e.Argument ?? new FeedReadWorkerInput { Feed = null, ForceRead = false }; // Setup for progress var currentProgress = 0; @@ -136,7 +136,7 @@ namespace FeedCenter // If we have a single feed then add it to the list - otherwise add them all if (workerInput.Feed != null) - feedsToRead.Add(database.Feeds.First(feed => feed.ID == workerInput.Feed.ID)); + feedsToRead.Add(database.Feeds.First(feed => feed.Id == workerInput.Feed.Id)); else feedsToRead.AddRange(database.Feeds); @@ -144,7 +144,7 @@ namespace FeedCenter foreach (var feed in feedsToRead) { // Read the feed - feed.Read(database, workerInput.ForceRead); + database.SaveChanges(() => feed.Read(database, workerInput.ForceRead)); // Increment progress currentProgress += 1; @@ -153,9 +153,6 @@ namespace FeedCenter worker.ReportProgress(currentProgress); } - // Save the changes - database.SaveChanges(); - // Increment progress currentProgress += 1; @@ -166,7 +163,7 @@ namespace FeedCenter if (DateTime.Now - Settings.Default.LastVersionCheck >= Settings.Default.VersionCheckInterval) { // Get the update information - UpdateCheck.CheckForUpdate(); + UpdateCheck.CheckForUpdate().Wait(); // Update the last check time Settings.Default.LastVersionCheck = DateTime.Now; diff --git a/Application/MainWindow/MainWindow.xaml.cs b/Application/MainWindow/MainWindow.xaml.cs index 21d3e0e..803213d 100644 --- a/Application/MainWindow/MainWindow.xaml.cs +++ b/Application/MainWindow/MainWindow.xaml.cs @@ -2,8 +2,10 @@ using Common.Helpers; using Common.IO; using Common.Update; +using FeedCenter.Data; using FeedCenter.Properties; using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows; @@ -18,7 +20,7 @@ namespace FeedCenter private int _feedIndex; private Category _currentCategory; - private IQueryable _feedList; + private IEnumerable _feedList; private Feed _currentFeed; public MainWindow() @@ -26,7 +28,7 @@ namespace FeedCenter InitializeComponent(); } - public void Initialize() + public async void Initialize() { // Setup the update handler InitializeUpdate(); @@ -48,7 +50,7 @@ namespace FeedCenter _feedReadWorker.RunWorkerCompleted += HandleFeedReadWorkerCompleted; // Setup the database - _database = new FeedCenterEntities(); + _database = Database.Entities; // Initialize the command line listener _commandLineListener = new InterprocessMessageListener(Properties.Resources.ApplicationName); @@ -65,7 +67,7 @@ namespace FeedCenter // Check for update if (Settings.Default.CheckVersionAtStartup) - UpdateCheck.CheckForUpdate(); + await UpdateCheck.CheckForUpdate(); // Show the link if updates are available if (UpdateCheck.UpdateAvailable) @@ -136,18 +138,18 @@ namespace FeedCenter private void InitializeDisplay() { // Get the last category (defaulting to none) - _currentCategory = _database.Categories.FirstOrDefault(category => category.ID.ToString() == Settings.Default.LastCategoryID); + _currentCategory = _database.Categories.FirstOrDefault(category => category.Id.ToString() == Settings.Default.LastCategoryID); DisplayCategory(); // Get the current feed list to match the category - _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.ID == _currentCategory.ID); + _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.Id == _currentCategory.Id); UpdateToolbarButtonState(); // Clear the link list LinkTextList.Items.Clear(); - // Reset the feed index + // Refresh the feed index _feedIndex = -1; // Start the timer @@ -341,11 +343,11 @@ namespace FeedCenter private void MarkAllItemsAsRead() { // Loop over all items and mark them as read - foreach (FeedItem feedItem in LinkTextList.Items) - feedItem.BeenRead = true; - - // Save the changes - _database.SaveChanges(); + _database.SaveChanges(() => + { + foreach (FeedItem feedItem in LinkTextList.Items) + feedItem.BeenRead = true; + }); // Clear the list LinkTextList.Items.Clear(); @@ -358,12 +360,12 @@ namespace FeedCenter private void ResetDatabase() { // Get the ID of the current feed - var currentId = _currentFeed?.ID ?? Guid.Empty; + var currentId = _currentFeed?.Id ?? Guid.Empty; // Create a new database object - _database = new FeedCenterEntities(); + _database.Refresh(); - _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.ID == _currentCategory.ID); + _feedList = _currentCategory == null ? _database.Feeds : _database.Feeds.Where(feed => feed.Category.Id == _currentCategory.Id); UpdateToolbarButtonState(); @@ -371,7 +373,7 @@ namespace FeedCenter var feedList = _feedList.OrderBy(f => f.Name).ToList(); // First try to find the current feed by ID to see if it is still there - var newIndex = feedList.FindIndex(f => f.ID == currentId); + var newIndex = feedList.FindIndex(f => f.Id == currentId); if (newIndex == -1) { diff --git a/Application/MainWindow/Toolbar.cs b/Application/MainWindow/Toolbar.cs index b862b84..46c6ddf 100644 --- a/Application/MainWindow/Toolbar.cs +++ b/Application/MainWindow/Toolbar.cs @@ -42,7 +42,7 @@ namespace FeedCenter if (BrowserCommon.OpenLink(browser, feedItem.Link)) { // Mark the feed as read - feedItem.BeenRead = true; + _database.SaveChanges(() => feedItem.BeenRead = true); // Remove the item LinkTextList.Items.Remove(feedItem); @@ -54,9 +54,6 @@ namespace FeedCenter // Switch to the normal sleep interval sleepInterval = settings.OpenAllSleepInterval; } - - // Save the changes - _database.SaveChanges(); } private void HandleOptionsToolbarButtonClick(object sender, RoutedEventArgs e) @@ -70,7 +67,7 @@ namespace FeedCenter // If okay was selected if (result.HasValue && result.Value) { - // Reset the database to current settings + // Refresh the database to current settings ResetDatabase(); // Re-initialize the feed display @@ -94,7 +91,7 @@ namespace FeedCenter // If okay was selected if (result.GetValueOrDefault()) { - // Reset the database to current settings + // Refresh the database to current settings ResetDatabase(); // Re-initialize the feed display @@ -156,7 +153,7 @@ namespace FeedCenter if (result.HasValue && result.Value) { // Save - _database.SaveChanges(); + _database.SaveChanges(() => { }); // Update feed DisplayFeed(); @@ -175,15 +172,8 @@ namespace FeedCenter // Move to the next feed NextFeed(); - // Delete all items - foreach (var item in feedToDelete.Items.ToList()) - _database.FeedItems.Remove(item); - // Delete the feed - _database.Feeds.Remove(feedToDelete); - - // Save - _database.SaveChanges(); + _database.SaveChanges(() => _database.Feeds.Remove(feedToDelete)); } private void OpenAllFeedItemsOnSinglePage() diff --git a/Application/MainWindow/WindowHandler.cs b/Application/MainWindow/WindowHandler.cs index 5e6dedc..6e17bb7 100644 --- a/Application/MainWindow/WindowHandler.cs +++ b/Application/MainWindow/WindowHandler.cs @@ -90,10 +90,7 @@ namespace FeedCenter SaveWindowSettings(); // Save settings - Settings.Default.Save(); - - // Save options - _database.SaveChanges(); + _database.SaveChanges(() => Settings.Default.Save()); // Get rid of the notification icon NotificationIcon.Dispose(); @@ -102,16 +99,14 @@ namespace FeedCenter private DelayedMethod _windowStateDelay; private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e) { - if (_windowStateDelay == null) - _windowStateDelay = new DelayedMethod(500, UpdateWindowSettings); + _windowStateDelay ??= new DelayedMethod(500, UpdateWindowSettings); _windowStateDelay.Reset(); } private void HandleWindowLocationChanged(object sender, EventArgs e) { - if (_windowStateDelay == null) - _windowStateDelay = new DelayedMethod(500, UpdateWindowSettings); + _windowStateDelay ??= new DelayedMethod(500, UpdateWindowSettings); _windowStateDelay.Reset(); } diff --git a/Application/Model.Context.cs b/Application/Model.Context.cs deleted file mode 100644 index 45a3afc..0000000 --- a/Application/Model.Context.cs +++ /dev/null @@ -1,34 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace FeedCenter -{ - using System; - using System.Data.Entity; - using System.Data.Entity.Infrastructure; - - public partial class FeedCenterEntities : DbContext - { - public FeedCenterEntities() - : base("name=FeedCenterEntities") - { - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - throw new UnintentionalCodeFirstException(); - } - - public virtual DbSet Categories { get; set; } - public virtual DbSet Feeds { get; set; } - public virtual DbSet FeedActions { get; set; } - public virtual DbSet FeedItems { get; set; } - public virtual DbSet Settings { get; set; } - } -} diff --git a/Application/Model.Context.tt b/Application/Model.Context.tt deleted file mode 100644 index cfb5c34..0000000 --- a/Application/Model.Context.tt +++ /dev/null @@ -1,636 +0,0 @@ -<#@ template language="C#" debug="false" hostspecific="true"#> -<#@ include file="EF6.Utility.CS.ttinclude"#><#@ - output extension=".cs"#><# - -const string inputFile = @"Model.edmx"; -var textTransform = DynamicTextTransformation.Create(this); -var code = new CodeGenerationTools(this); -var ef = new MetadataTools(this); -var typeMapper = new TypeMapper(code, ef, textTransform.Errors); -var loader = new EdmMetadataLoader(textTransform.Host, textTransform.Errors); -var itemCollection = loader.CreateEdmItemCollection(inputFile); -var modelNamespace = loader.GetModelNamespace(inputFile); -var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); - -var container = itemCollection.OfType().FirstOrDefault(); -if (container == null) -{ - return string.Empty; -} -#> -//------------------------------------------------------------------------------ -// -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#> -// -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#> -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#> -// -//------------------------------------------------------------------------------ - -<# - -var codeNamespace = code.VsNamespaceSuggestion(); -if (!String.IsNullOrEmpty(codeNamespace)) -{ -#> -namespace <#=code.EscapeNamespace(codeNamespace)#> -{ -<# - PushIndent(" "); -} - -#> -using System; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -<# -if (container.FunctionImports.Any()) -{ -#> -using System.Data.Entity.Core.Objects; -using System.Linq; -<# -} -#> - -<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext -{ - public <#=code.Escape(container)#>() - : base("name=<#=container.Name#>") - { -<# -if (!loader.IsLazyLoadingEnabled(container)) -{ -#> - this.Configuration.LazyLoadingEnabled = false; -<# -} - -foreach (var entitySet in container.BaseEntitySets.OfType()) -{ - // Note: the DbSet members are defined below such that the getter and - // setter always have the same accessibility as the DbSet definition - if (Accessibility.ForReadOnlyProperty(entitySet) != "public") - { -#> - <#=codeStringGenerator.DbSetInitializer(entitySet)#> -<# - } -} -#> - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - throw new UnintentionalCodeFirstException(); - } - -<# - foreach (var entitySet in container.BaseEntitySets.OfType()) - { -#> - <#=codeStringGenerator.DbSet(entitySet)#> -<# - } - - foreach (var edmFunction in container.FunctionImports) - { - WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: false); - } -#> -} -<# - -if (!String.IsNullOrEmpty(codeNamespace)) -{ - PopIndent(); -#> -} -<# -} -#> -<#+ - -private void WriteFunctionImport(TypeMapper typeMapper, CodeStringGenerator codeStringGenerator, EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) -{ - if (typeMapper.IsComposable(edmFunction)) - { -#> - - [DbFunction("<#=edmFunction.NamespaceName#>", "<#=edmFunction.Name#>")] - <#=codeStringGenerator.ComposableFunctionMethod(edmFunction, modelNamespace)#> - { -<#+ - codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter); -#> - <#=codeStringGenerator.ComposableCreateQuery(edmFunction, modelNamespace)#> - } -<#+ - } - else - { -#> - - <#=codeStringGenerator.FunctionMethod(edmFunction, modelNamespace, includeMergeOption)#> - { -<#+ - codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter); -#> - <#=codeStringGenerator.ExecuteFunction(edmFunction, modelNamespace, includeMergeOption)#> - } -<#+ - if (typeMapper.GenerateMergeOptionFunction(edmFunction, includeMergeOption)) - { - WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: true); - } - } -} - -public void WriteFunctionParameter(string name, string isNotNull, string notNullInit, string nullInit) -{ -#> - var <#=name#> = <#=isNotNull#> ? - <#=notNullInit#> : - <#=nullInit#>; - -<#+ -} - -public const string TemplateId = "CSharp_DbContext_Context_EF6"; - -public class CodeStringGenerator -{ - private readonly CodeGenerationTools _code; - private readonly TypeMapper _typeMapper; - private readonly MetadataTools _ef; - - public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef) - { - ArgumentNotNull(code, "code"); - ArgumentNotNull(typeMapper, "typeMapper"); - ArgumentNotNull(ef, "ef"); - - _code = code; - _typeMapper = typeMapper; - _ef = ef; - } - - public string Property(EdmProperty edmProperty) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2} {{ {3}get; {4}set; }}", - Accessibility.ForProperty(edmProperty), - _typeMapper.GetTypeName(edmProperty.TypeUsage), - _code.Escape(edmProperty), - _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), - _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); - } - - public string NavigationProperty(NavigationProperty navProp) - { - var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType()); - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2} {{ {3}get; {4}set; }}", - AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)), - navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, - _code.Escape(navProp), - _code.SpaceAfter(Accessibility.ForGetter(navProp)), - _code.SpaceAfter(Accessibility.ForSetter(navProp))); - } - - public string AccessibilityAndVirtual(string accessibility) - { - return accessibility + (accessibility != "private" ? " virtual" : ""); - } - - public string EntityClassOpening(EntityType entity) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1}partial class {2}{3}", - Accessibility.ForType(entity), - _code.SpaceAfter(_code.AbstractOption(entity)), - _code.Escape(entity), - _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); - } - - public string EnumOpening(SimpleType enumType) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} enum {1} : {2}", - Accessibility.ForType(enumType), - _code.Escape(enumType), - _code.Escape(_typeMapper.UnderlyingClrType(enumType))); - } - - public void WriteFunctionParameters(EdmFunction edmFunction, Action writeParameter) - { - var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); - foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable)) - { - var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"; - var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")"; - var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))"; - writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit); - } - } - - public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace) - { - var parameters = _typeMapper.GetParameters(edmFunction); - - return string.Format( - CultureInfo.InvariantCulture, - "{0} IQueryable<{1}> {2}({3})", - AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), - _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), - _code.Escape(edmFunction), - string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray())); - } - - public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace) - { - var parameters = _typeMapper.GetParameters(edmFunction); - - return string.Format( - CultureInfo.InvariantCulture, - "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});", - _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), - edmFunction.NamespaceName, - edmFunction.Name, - string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()), - _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))); - } - - public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) - { - var parameters = _typeMapper.GetParameters(edmFunction); - var returnType = _typeMapper.GetReturnType(edmFunction); - - var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()); - if (includeMergeOption) - { - paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption"; - } - - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2}({3})", - AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), - returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", - _code.Escape(edmFunction), - paramList); - } - - public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) - { - var parameters = _typeMapper.GetParameters(edmFunction); - var returnType = _typeMapper.GetReturnType(edmFunction); - - var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())); - if (includeMergeOption) - { - callParams = ", mergeOption" + callParams; - } - - return string.Format( - CultureInfo.InvariantCulture, - "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});", - returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", - edmFunction.Name, - callParams); - } - - public string DbSet(EntitySet entitySet) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} virtual DbSet<{1}> {2} {{ get; set; }}", - Accessibility.ForReadOnlyProperty(entitySet), - _typeMapper.GetTypeName(entitySet.ElementType), - _code.Escape(entitySet)); - } - - public string DbSetInitializer(EntitySet entitySet) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} = Set<{1}>();", - _code.Escape(entitySet), - _typeMapper.GetTypeName(entitySet.ElementType)); - } - - public string UsingDirectives(bool inHeader, bool includeCollections = true) - { - return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) - ? string.Format( - CultureInfo.InvariantCulture, - "{0}using System;{1}" + - "{2}", - inHeader ? Environment.NewLine : "", - includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", - inHeader ? "" : Environment.NewLine) - : ""; - } -} - -public class TypeMapper -{ - private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName"; - - private readonly System.Collections.IList _errors; - private readonly CodeGenerationTools _code; - private readonly MetadataTools _ef; - - public static string FixNamespaces(string typeName) - { - return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial."); - } - - public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors) - { - ArgumentNotNull(code, "code"); - ArgumentNotNull(ef, "ef"); - ArgumentNotNull(errors, "errors"); - - _code = code; - _ef = ef; - _errors = errors; - } - - public string GetTypeName(TypeUsage typeUsage) - { - return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null); - } - - public string GetTypeName(EdmType edmType) - { - return GetTypeName(edmType, isNullable: null, modelNamespace: null); - } - - public string GetTypeName(TypeUsage typeUsage, string modelNamespace) - { - return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace); - } - - public string GetTypeName(EdmType edmType, string modelNamespace) - { - return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace); - } - - public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) - { - if (edmType == null) - { - return null; - } - - var collectionType = edmType as CollectionType; - if (collectionType != null) - { - return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); - } - - var typeName = _code.Escape(edmType.MetadataProperties - .Where(p => p.Name == ExternalTypeNameAttributeName) - .Select(p => (string)p.Value) - .FirstOrDefault()) - ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? - _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : - _code.Escape(edmType)); - - if (edmType is StructuralType) - { - return typeName; - } - - if (edmType is SimpleType) - { - var clrType = UnderlyingClrType(edmType); - if (!IsEnumType(edmType)) - { - typeName = _code.Escape(clrType); - } - - typeName = FixNamespaces(typeName); - - return clrType.IsValueType && isNullable == true ? - String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) : - typeName; - } - - throw new ArgumentException("edmType"); - } - - public Type UnderlyingClrType(EdmType edmType) - { - ArgumentNotNull(edmType, "edmType"); - - var primitiveType = edmType as PrimitiveType; - if (primitiveType != null) - { - return primitiveType.ClrEquivalentType; - } - - if (IsEnumType(edmType)) - { - return GetEnumUnderlyingType(edmType).ClrEquivalentType; - } - - return typeof(object); - } - - public object GetEnumMemberValue(MetadataItem enumMember) - { - ArgumentNotNull(enumMember, "enumMember"); - - var valueProperty = enumMember.GetType().GetProperty("Value"); - return valueProperty == null ? null : valueProperty.GetValue(enumMember, null); - } - - public string GetEnumMemberName(MetadataItem enumMember) - { - ArgumentNotNull(enumMember, "enumMember"); - - var nameProperty = enumMember.GetType().GetProperty("Name"); - return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null); - } - - public System.Collections.IEnumerable GetEnumMembers(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - var membersProperty = enumType.GetType().GetProperty("Members"); - return membersProperty != null - ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null) - : Enumerable.Empty(); - } - - public bool EnumIsFlags(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - var isFlagsProperty = enumType.GetType().GetProperty("IsFlags"); - return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null); - } - - public bool IsEnumType(GlobalItem edmType) - { - ArgumentNotNull(edmType, "edmType"); - - return edmType.GetType().Name == "EnumType"; - } - - public PrimitiveType GetEnumUnderlyingType(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null); - } - - public string CreateLiteral(object value) - { - if (value == null || value.GetType() != typeof(TimeSpan)) - { - return _code.CreateLiteral(value); - } - - return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks); - } - - public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable types, string sourceFile) - { - ArgumentNotNull(types, "types"); - ArgumentNotNull(sourceFile, "sourceFile"); - - var hash = new HashSet(StringComparer.InvariantCultureIgnoreCase); - if (types.Any(item => !hash.Add(item))) - { - _errors.Add( - new CompilerError(sourceFile, -1, -1, "6023", - String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict")))); - return false; - } - return true; - } - - public IEnumerable GetEnumItemsToGenerate(IEnumerable itemCollection) - { - return GetItemsToGenerate(itemCollection) - .Where(e => IsEnumType(e)); - } - - public IEnumerable GetItemsToGenerate(IEnumerable itemCollection) where T: EdmType - { - return itemCollection - .OfType() - .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) - .OrderBy(i => i.Name); - } - - public IEnumerable GetAllGlobalItems(IEnumerable itemCollection) - { - return itemCollection - .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i)) - .Select(g => GetGlobalItemName(g)); - } - - public string GetGlobalItemName(GlobalItem item) - { - if (item is EdmType) - { - return ((EdmType)item).Name; - } - else - { - return ((EntityContainer)item).Name; - } - } - - public IEnumerable GetSimpleProperties(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); - } - - public IEnumerable GetSimpleProperties(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); - } - - public IEnumerable GetComplexProperties(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); - } - - public IEnumerable GetComplexProperties(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); - } - - public IEnumerable GetPropertiesWithDefaultValues(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); - } - - public IEnumerable GetPropertiesWithDefaultValues(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); - } - - public IEnumerable GetNavigationProperties(EntityType type) - { - return type.NavigationProperties.Where(np => np.DeclaringType == type); - } - - public IEnumerable GetCollectionNavigationProperties(EntityType type) - { - return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); - } - - public FunctionParameter GetReturnParameter(EdmFunction edmFunction) - { - ArgumentNotNull(edmFunction, "edmFunction"); - - var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters"); - return returnParamsProperty == null - ? edmFunction.ReturnParameter - : ((IEnumerable)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault(); - } - - public bool IsComposable(EdmFunction edmFunction) - { - ArgumentNotNull(edmFunction, "edmFunction"); - - var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute"); - return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null); - } - - public IEnumerable GetParameters(EdmFunction edmFunction) - { - return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); - } - - public TypeUsage GetReturnType(EdmFunction edmFunction) - { - var returnParam = GetReturnParameter(edmFunction); - return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage); - } - - public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption) - { - var returnType = GetReturnType(edmFunction); - return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; - } -} - -public static void ArgumentNotNull(T arg, string name) where T : class -{ - if (arg == null) - { - throw new ArgumentNullException(name); - } -} -#> \ No newline at end of file diff --git a/Application/Model.Designer.cs b/Application/Model.Designer.cs deleted file mode 100644 index c582988..0000000 --- a/Application/Model.Designer.cs +++ /dev/null @@ -1,10 +0,0 @@ -// T4 code generation is enabled for model 'D:\Code\Personal\FeedCenter\Application\Model.edmx'. -// To enable legacy code generation, change the value of the 'Code Generation Strategy' designer -// property to 'Legacy ObjectContext'. This property is available in the Properties Window when the model -// is open in the designer. - -// If no context and entity classes have been generated, it may be because you created an empty model but -// have not yet chosen which version of Entity Framework to use. To generate a context class and entity -// classes for your model, open the model in the designer, right-click on the designer surface, and -// select 'Update Model from Database...', 'Generate Database from Model...', or 'Add Code Generation -// Item...'. \ No newline at end of file diff --git a/Application/Model.cs b/Application/Model.cs deleted file mode 100644 index 7cc0662..0000000 --- a/Application/Model.cs +++ /dev/null @@ -1,9 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated from a template. -// -// Manual changes to this file may cause unexpected behavior in your application. -// Manual changes to this file will be overwritten if the code is regenerated. -// -//------------------------------------------------------------------------------ - diff --git a/Application/Model.edmx b/Application/Model.edmx deleted file mode 100644 index 8feef63..0000000 --- a/Application/Model.edmx +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Application/Model.tt b/Application/Model.tt deleted file mode 100644 index 1205534..0000000 --- a/Application/Model.tt +++ /dev/null @@ -1,726 +0,0 @@ -<#@ template language="C#" debug="false" hostspecific="true"#> -<#@ include file="EF6.Utility.CS.ttinclude"#><#@ - output extension=".cs"#><# - -const string inputFile = @"Model.edmx"; -var textTransform = DynamicTextTransformation.Create(this); -var code = new CodeGenerationTools(this); -var ef = new MetadataTools(this); -var typeMapper = new TypeMapper(code, ef, textTransform.Errors); -var fileManager = EntityFrameworkTemplateFileManager.Create(this); -var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile); -var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef); - -if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile)) -{ - return string.Empty; -} - -WriteHeader(codeStringGenerator, fileManager); - -foreach (var entity in typeMapper.GetItemsToGenerate(itemCollection)) -{ - fileManager.StartNewFile(entity.Name + ".cs"); - BeginNamespace(code); -#> -<#=codeStringGenerator.UsingDirectives(inHeader: false)#> -<#=codeStringGenerator.EntityClassOpening(entity)#> -{ -<# - var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity); - var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity); - var complexProperties = typeMapper.GetComplexProperties(entity); - - if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any()) - { -#> - public <#=code.Escape(entity)#>() - { -<# - foreach (var edmProperty in propertiesWithDefaultValues) - { -#> - this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; -<# - } - - foreach (var navigationProperty in collectionNavigationProperties) - { -#> - this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>(); -<# - } - - foreach (var complexProperty in complexProperties) - { -#> - this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); -<# - } -#> - } - -<# - } - - var simpleProperties = typeMapper.GetSimpleProperties(entity); - if (simpleProperties.Any()) - { - foreach (var edmProperty in simpleProperties) - { -#> - <#=codeStringGenerator.Property(edmProperty)#> -<# - } - } - - if (complexProperties.Any()) - { -#> - -<# - foreach(var complexProperty in complexProperties) - { -#> - <#=codeStringGenerator.Property(complexProperty)#> -<# - } - } - - var navigationProperties = typeMapper.GetNavigationProperties(entity); - if (navigationProperties.Any()) - { -#> - -<# - foreach (var navigationProperty in navigationProperties) - { -#> - <#=codeStringGenerator.NavigationProperty(navigationProperty)#> -<# - } - } -#> -} -<# - EndNamespace(code); -} - -foreach (var complex in typeMapper.GetItemsToGenerate(itemCollection)) -{ - fileManager.StartNewFile(complex.Name + ".cs"); - BeginNamespace(code); -#> -<#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> -<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> -{ -<# - var complexProperties = typeMapper.GetComplexProperties(complex); - var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(complex); - - if (propertiesWithDefaultValues.Any() || complexProperties.Any()) - { -#> - public <#=code.Escape(complex)#>() - { -<# - foreach (var edmProperty in propertiesWithDefaultValues) - { -#> - this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>; -<# - } - - foreach (var complexProperty in complexProperties) - { -#> - this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>(); -<# - } -#> - } - -<# - } - - var simpleProperties = typeMapper.GetSimpleProperties(complex); - if (simpleProperties.Any()) - { - foreach(var edmProperty in simpleProperties) - { -#> - <#=codeStringGenerator.Property(edmProperty)#> -<# - } - } - - if (complexProperties.Any()) - { -#> - -<# - foreach(var edmProperty in complexProperties) - { -#> - <#=codeStringGenerator.Property(edmProperty)#> -<# - } - } -#> -} -<# - EndNamespace(code); -} - -foreach (var enumType in typeMapper.GetEnumItemsToGenerate(itemCollection)) -{ - fileManager.StartNewFile(enumType.Name + ".cs"); - BeginNamespace(code); -#> -<#=codeStringGenerator.UsingDirectives(inHeader: false, includeCollections: false)#> -<# - if (typeMapper.EnumIsFlags(enumType)) - { -#> -[Flags] -<# - } -#> -<#=codeStringGenerator.EnumOpening(enumType)#> -{ -<# - var foundOne = false; - - foreach (MetadataItem member in typeMapper.GetEnumMembers(enumType)) - { - foundOne = true; -#> - <#=code.Escape(typeMapper.GetEnumMemberName(member))#> = <#=typeMapper.GetEnumMemberValue(member)#>, -<# - } - - if (foundOne) - { - this.GenerationEnvironment.Remove(this.GenerationEnvironment.Length - 3, 1); - } -#> -} -<# - EndNamespace(code); -} - -fileManager.Process(); - -#> -<#+ - -public void WriteHeader(CodeStringGenerator codeStringGenerator, EntityFrameworkTemplateFileManager fileManager) -{ - fileManager.StartHeader(); -#> -//------------------------------------------------------------------------------ -// -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#> -// -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#> -// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#> -// -//------------------------------------------------------------------------------ -<#=codeStringGenerator.UsingDirectives(inHeader: true)#> -<#+ - fileManager.EndBlock(); -} - -public void BeginNamespace(CodeGenerationTools code) -{ - var codeNamespace = code.VsNamespaceSuggestion(); - if (!String.IsNullOrEmpty(codeNamespace)) - { -#> -namespace <#=code.EscapeNamespace(codeNamespace)#> -{ -<#+ - PushIndent(" "); - } -} - -public void EndNamespace(CodeGenerationTools code) -{ - if (!String.IsNullOrEmpty(code.VsNamespaceSuggestion())) - { - PopIndent(); -#> -} -<#+ - } -} - -public const string TemplateId = "CSharp_DbContext_Types_EF6"; - -public class CodeStringGenerator -{ - private readonly CodeGenerationTools _code; - private readonly TypeMapper _typeMapper; - private readonly MetadataTools _ef; - - public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef) - { - ArgumentNotNull(code, "code"); - ArgumentNotNull(typeMapper, "typeMapper"); - ArgumentNotNull(ef, "ef"); - - _code = code; - _typeMapper = typeMapper; - _ef = ef; - } - - public string Property(EdmProperty edmProperty) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2} {{ {3}get; {4}set; }}", - Accessibility.ForProperty(edmProperty), - _typeMapper.GetTypeName(edmProperty.TypeUsage), - _code.Escape(edmProperty), - _code.SpaceAfter(Accessibility.ForGetter(edmProperty)), - _code.SpaceAfter(Accessibility.ForSetter(edmProperty))); - } - - public string NavigationProperty(NavigationProperty navProp) - { - var endType = _typeMapper.GetTypeName(navProp.ToEndMember.GetEntityType()); - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2} {{ {3}get; {4}set; }}", - AccessibilityAndVirtual(Accessibility.ForNavigationProperty(navProp)), - navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType, - _code.Escape(navProp), - _code.SpaceAfter(Accessibility.ForGetter(navProp)), - _code.SpaceAfter(Accessibility.ForSetter(navProp))); - } - - public string AccessibilityAndVirtual(string accessibility) - { - return accessibility + (accessibility != "private" ? " virtual" : ""); - } - - public string EntityClassOpening(EntityType entity) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1}partial class {2}{3}", - Accessibility.ForType(entity), - _code.SpaceAfter(_code.AbstractOption(entity)), - _code.Escape(entity), - _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType))); - } - - public string EnumOpening(SimpleType enumType) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} enum {1} : {2}", - Accessibility.ForType(enumType), - _code.Escape(enumType), - _code.Escape(_typeMapper.UnderlyingClrType(enumType))); - } - - public void WriteFunctionParameters(EdmFunction edmFunction, Action writeParameter) - { - var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); - foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable)) - { - var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null"; - var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", " + parameter.FunctionParameterName + ")"; - var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\", typeof(" + TypeMapper.FixNamespaces(parameter.RawClrTypeName) + "))"; - writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit); - } - } - - public string ComposableFunctionMethod(EdmFunction edmFunction, string modelNamespace) - { - var parameters = _typeMapper.GetParameters(edmFunction); - - return string.Format( - CultureInfo.InvariantCulture, - "{0} IQueryable<{1}> {2}({3})", - AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), - _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), - _code.Escape(edmFunction), - string.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray())); - } - - public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace) - { - var parameters = _typeMapper.GetParameters(edmFunction); - - return string.Format( - CultureInfo.InvariantCulture, - "return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});", - _typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace), - edmFunction.NamespaceName, - edmFunction.Name, - string.Join(", ", parameters.Select(p => "@" + p.EsqlParameterName).ToArray()), - _code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray()))); - } - - public string FunctionMethod(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) - { - var parameters = _typeMapper.GetParameters(edmFunction); - var returnType = _typeMapper.GetReturnType(edmFunction); - - var paramList = String.Join(", ", parameters.Select(p => TypeMapper.FixNamespaces(p.FunctionParameterType) + " " + p.FunctionParameterName).ToArray()); - if (includeMergeOption) - { - paramList = _code.StringAfter(paramList, ", ") + "MergeOption mergeOption"; - } - - return string.Format( - CultureInfo.InvariantCulture, - "{0} {1} {2}({3})", - AccessibilityAndVirtual(Accessibility.ForMethod(edmFunction)), - returnType == null ? "int" : "ObjectResult<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", - _code.Escape(edmFunction), - paramList); - } - - public string ExecuteFunction(EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) - { - var parameters = _typeMapper.GetParameters(edmFunction); - var returnType = _typeMapper.GetReturnType(edmFunction); - - var callParams = _code.StringBefore(", ", String.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())); - if (includeMergeOption) - { - callParams = ", mergeOption" + callParams; - } - - return string.Format( - CultureInfo.InvariantCulture, - "return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction{0}(\"{1}\"{2});", - returnType == null ? "" : "<" + _typeMapper.GetTypeName(returnType, modelNamespace) + ">", - edmFunction.Name, - callParams); - } - - public string DbSet(EntitySet entitySet) - { - return string.Format( - CultureInfo.InvariantCulture, - "{0} virtual DbSet<{1}> {2} {{ get; set; }}", - Accessibility.ForReadOnlyProperty(entitySet), - _typeMapper.GetTypeName(entitySet.ElementType), - _code.Escape(entitySet)); - } - - public string UsingDirectives(bool inHeader, bool includeCollections = true) - { - return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion()) - ? string.Format( - CultureInfo.InvariantCulture, - "{0}using System;{1}" + - "{2}", - inHeader ? Environment.NewLine : "", - includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "", - inHeader ? "" : Environment.NewLine) - : ""; - } -} - -public class TypeMapper -{ - private const string ExternalTypeNameAttributeName = @"http://schemas.microsoft.com/ado/2006/04/codegeneration:ExternalTypeName"; - - private readonly System.Collections.IList _errors; - private readonly CodeGenerationTools _code; - private readonly MetadataTools _ef; - - public TypeMapper(CodeGenerationTools code, MetadataTools ef, System.Collections.IList errors) - { - ArgumentNotNull(code, "code"); - ArgumentNotNull(ef, "ef"); - ArgumentNotNull(errors, "errors"); - - _code = code; - _ef = ef; - _errors = errors; - } - - public static string FixNamespaces(string typeName) - { - return typeName.Replace("System.Data.Spatial.", "System.Data.Entity.Spatial."); - } - - public string GetTypeName(TypeUsage typeUsage) - { - return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace: null); - } - - public string GetTypeName(EdmType edmType) - { - return GetTypeName(edmType, isNullable: null, modelNamespace: null); - } - - public string GetTypeName(TypeUsage typeUsage, string modelNamespace) - { - return typeUsage == null ? null : GetTypeName(typeUsage.EdmType, _ef.IsNullable(typeUsage), modelNamespace); - } - - public string GetTypeName(EdmType edmType, string modelNamespace) - { - return GetTypeName(edmType, isNullable: null, modelNamespace: modelNamespace); - } - - public string GetTypeName(EdmType edmType, bool? isNullable, string modelNamespace) - { - if (edmType == null) - { - return null; - } - - var collectionType = edmType as CollectionType; - if (collectionType != null) - { - return String.Format(CultureInfo.InvariantCulture, "ICollection<{0}>", GetTypeName(collectionType.TypeUsage, modelNamespace)); - } - - var typeName = _code.Escape(edmType.MetadataProperties - .Where(p => p.Name == ExternalTypeNameAttributeName) - .Select(p => (string)p.Value) - .FirstOrDefault()) - ?? (modelNamespace != null && edmType.NamespaceName != modelNamespace ? - _code.CreateFullName(_code.EscapeNamespace(edmType.NamespaceName), _code.Escape(edmType)) : - _code.Escape(edmType)); - - if (edmType is StructuralType) - { - return typeName; - } - - if (edmType is SimpleType) - { - var clrType = UnderlyingClrType(edmType); - if (!IsEnumType(edmType)) - { - typeName = _code.Escape(clrType); - } - - typeName = FixNamespaces(typeName); - - return clrType.IsValueType && isNullable == true ? - String.Format(CultureInfo.InvariantCulture, "Nullable<{0}>", typeName) : - typeName; - } - - throw new ArgumentException("edmType"); - } - - public Type UnderlyingClrType(EdmType edmType) - { - ArgumentNotNull(edmType, "edmType"); - - var primitiveType = edmType as PrimitiveType; - if (primitiveType != null) - { - return primitiveType.ClrEquivalentType; - } - - if (IsEnumType(edmType)) - { - return GetEnumUnderlyingType(edmType).ClrEquivalentType; - } - - return typeof(object); - } - - public object GetEnumMemberValue(MetadataItem enumMember) - { - ArgumentNotNull(enumMember, "enumMember"); - - var valueProperty = enumMember.GetType().GetProperty("Value"); - return valueProperty == null ? null : valueProperty.GetValue(enumMember, null); - } - - public string GetEnumMemberName(MetadataItem enumMember) - { - ArgumentNotNull(enumMember, "enumMember"); - - var nameProperty = enumMember.GetType().GetProperty("Name"); - return nameProperty == null ? null : (string)nameProperty.GetValue(enumMember, null); - } - - public System.Collections.IEnumerable GetEnumMembers(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - var membersProperty = enumType.GetType().GetProperty("Members"); - return membersProperty != null - ? (System.Collections.IEnumerable)membersProperty.GetValue(enumType, null) - : Enumerable.Empty(); - } - - public bool EnumIsFlags(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - var isFlagsProperty = enumType.GetType().GetProperty("IsFlags"); - return isFlagsProperty != null && (bool)isFlagsProperty.GetValue(enumType, null); - } - - public bool IsEnumType(GlobalItem edmType) - { - ArgumentNotNull(edmType, "edmType"); - - return edmType.GetType().Name == "EnumType"; - } - - public PrimitiveType GetEnumUnderlyingType(EdmType enumType) - { - ArgumentNotNull(enumType, "enumType"); - - return (PrimitiveType)enumType.GetType().GetProperty("UnderlyingType").GetValue(enumType, null); - } - - public string CreateLiteral(object value) - { - if (value == null || value.GetType() != typeof(TimeSpan)) - { - return _code.CreateLiteral(value); - } - - return string.Format(CultureInfo.InvariantCulture, "new TimeSpan({0})", ((TimeSpan)value).Ticks); - } - - public bool VerifyCaseInsensitiveTypeUniqueness(IEnumerable types, string sourceFile) - { - ArgumentNotNull(types, "types"); - ArgumentNotNull(sourceFile, "sourceFile"); - - var hash = new HashSet(StringComparer.InvariantCultureIgnoreCase); - if (types.Any(item => !hash.Add(item))) - { - _errors.Add( - new CompilerError(sourceFile, -1, -1, "6023", - String.Format(CultureInfo.CurrentCulture, CodeGenerationTools.GetResourceString("Template_CaseInsensitiveTypeConflict")))); - return false; - } - return true; - } - - public IEnumerable GetEnumItemsToGenerate(IEnumerable itemCollection) - { - return GetItemsToGenerate(itemCollection) - .Where(e => IsEnumType(e)); - } - - public IEnumerable GetItemsToGenerate(IEnumerable itemCollection) where T: EdmType - { - return itemCollection - .OfType() - .Where(i => !i.MetadataProperties.Any(p => p.Name == ExternalTypeNameAttributeName)) - .OrderBy(i => i.Name); - } - - public IEnumerable GetAllGlobalItems(IEnumerable itemCollection) - { - return itemCollection - .Where(i => i is EntityType || i is ComplexType || i is EntityContainer || IsEnumType(i)) - .Select(g => GetGlobalItemName(g)); - } - - public string GetGlobalItemName(GlobalItem item) - { - if (item is EdmType) - { - return ((EdmType)item).Name; - } - else - { - return ((EntityContainer)item).Name; - } - } - - public IEnumerable GetSimpleProperties(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); - } - - public IEnumerable GetSimpleProperties(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type); - } - - public IEnumerable GetComplexProperties(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); - } - - public IEnumerable GetComplexProperties(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == type); - } - - public IEnumerable GetPropertiesWithDefaultValues(EntityType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); - } - - public IEnumerable GetPropertiesWithDefaultValues(ComplexType type) - { - return type.Properties.Where(p => p.TypeUsage.EdmType is SimpleType && p.DeclaringType == type && p.DefaultValue != null); - } - - public IEnumerable GetNavigationProperties(EntityType type) - { - return type.NavigationProperties.Where(np => np.DeclaringType == type); - } - - public IEnumerable GetCollectionNavigationProperties(EntityType type) - { - return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many); - } - - public FunctionParameter GetReturnParameter(EdmFunction edmFunction) - { - ArgumentNotNull(edmFunction, "edmFunction"); - - var returnParamsProperty = edmFunction.GetType().GetProperty("ReturnParameters"); - return returnParamsProperty == null - ? edmFunction.ReturnParameter - : ((IEnumerable)returnParamsProperty.GetValue(edmFunction, null)).FirstOrDefault(); - } - - public bool IsComposable(EdmFunction edmFunction) - { - ArgumentNotNull(edmFunction, "edmFunction"); - - var isComposableProperty = edmFunction.GetType().GetProperty("IsComposableAttribute"); - return isComposableProperty != null && (bool)isComposableProperty.GetValue(edmFunction, null); - } - - public IEnumerable GetParameters(EdmFunction edmFunction) - { - return FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef); - } - - public TypeUsage GetReturnType(EdmFunction edmFunction) - { - var returnParam = GetReturnParameter(edmFunction); - return returnParam == null ? null : _ef.GetElementType(returnParam.TypeUsage); - } - - public bool GenerateMergeOptionFunction(EdmFunction edmFunction, bool includeMergeOption) - { - var returnType = GetReturnType(edmFunction); - return !includeMergeOption && returnType != null && returnType.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; - } -} - -public static void ArgumentNotNull(T arg, string name) where T : class -{ - if (arg == null) - { - throw new ArgumentNullException(name); - } -} -#> \ No newline at end of file diff --git a/Application/NotificationIcon.cs b/Application/NotificationIcon.cs index e345e1b..d0e558b 100644 --- a/Application/NotificationIcon.cs +++ b/Application/NotificationIcon.cs @@ -54,7 +54,7 @@ namespace FeedCenter // Toggle the lock setting Settings.Default.WindowLocked = !Settings.Default.WindowLocked; - // Reset the menu choice + // Refresh the menu choice ((ToolStripMenuItem) sender).Checked = Settings.Default.WindowLocked; } diff --git a/Application/Options/AboutOptionsPanel.xaml.cs b/Application/Options/AboutOptionsPanel.xaml.cs index 44cbef4..3336a7c 100644 --- a/Application/Options/AboutOptionsPanel.xaml.cs +++ b/Application/Options/AboutOptionsPanel.xaml.cs @@ -16,7 +16,7 @@ namespace FeedCenter.Options ApplicationNameLabel.Text = Properties.Resources.ApplicationDisplayName; - string version = UpdateCheck.LocalVersion.ToString(); + var version = UpdateCheck.LocalVersion.ToString(); VersionLabel.Text = string.Format(Properties.Resources.Version, version); CompanyLabel.Text = ((AssemblyCompanyAttribute) Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false)[0]).Company; diff --git a/Application/Options/BulkFeedWindow.xaml.cs b/Application/Options/BulkFeedWindow.xaml.cs index c243cc5..141cc1e 100644 --- a/Application/Options/BulkFeedWindow.xaml.cs +++ b/Application/Options/BulkFeedWindow.xaml.cs @@ -22,7 +22,7 @@ namespace FeedCenter.Options { _checkedListBoxItems = new List>(); - foreach (var feed in database.AllFeeds) + foreach (var feed in database.Feeds) _checkedListBoxItems.Add(new CheckedListItem { Item = feed }); _collectionViewSource = new CollectionViewSource { Source = _checkedListBoxItems }; diff --git a/Application/Options/FeedWindow.xaml b/Application/Options/FeedWindow.xaml index bddfb9b..ea34eeb 100644 --- a/Application/Options/FeedWindow.xaml +++ b/Application/Options/FeedWindow.xaml @@ -3,6 +3,11 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:properties="clr-namespace:FeedCenter.Properties" xmlns:feedCenter="clr-namespace:FeedCenter" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + d:DataContext="{d:DesignInstance Type=feedCenter:Feed}" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:validation="clr-namespace:Common.Wpf.Validation;assembly=Common.Wpf" + mc:Ignorable="d" Title="FeedWindow" Height="300" Width="450" @@ -33,8 +38,15 @@ + Margin="6"> + + + + + + + +