83.01 Wpf Custom user controls for Manuscript View (Wpf) - chempkovsky/CS2WPF-and-CS2XAMARIN GitHub Wiki

  • Preparation steps to first run Dm04WebApp
    • Set up default constructor of LitDbContext
        public LitDbContext() : base("name=LitConnection") { }
- Set up connection strings in the Web.config
    <add name="DefaultConnection"
    connectionString="Data Source=SVR2016SQL2017;Initial Catalog=AspNetDm04WebAppSecurity;Persist Security Info=True;User ID=sa;Password=YOUR_PASSWORD"
    providerName="System.Data.SqlClient" />
    <add name="LitConnection"
    connectionString="Data Source=SVR2016SQL2017;Initial Catalog=LitStorageDm04WebApp;Persist Security Info=True;User ID=sa;Password=YOUR_PASSWORD"
    providerName="System.Data.SqlClient" />
- Db Migration is not used for this demo app. Instead the following code have been executed in the small console app to create  Data Base on the SQL server. At the moment, tables of countries, languages and dialects must be populated with data. Please add a static class to the console app:
    public static class DbHelpers
    {
        public static void PopulateCounties(this LitDbContext db)
        {
            CultureInfo[] cultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures & CultureTypes.SpecificCultures);
            foreach (CultureInfo cultureInfo in cultureInfos)
            {
                if (string.IsNullOrEmpty(cultureInfo.Name)) continue;
                RegionInfo regionInfo = new RegionInfo(cultureInfo.Name);
                if (!db.LitCountryDbSet.Any(c => (c.Iso3 == regionInfo.ThreeLetterISORegionName) && (c.Iso2 == regionInfo.TwoLetterISORegionName)))
                {
                    LitCountry сountry = new LitCountry()
                    {
                        Iso3 = regionInfo.ThreeLetterISORegionName,
                        Iso2 = regionInfo.TwoLetterISORegionName,
                        CountryName = regionInfo.EnglishName
                    };
                    db.LitCountryDbSet.Add(сountry);
                    db.SaveChanges();
                    db.Entry(сountry).State = System.Data.Entity.EntityState.Detached;
                }
            }
        }
        public static void PopulateLanguages(this LitDbContext db)
        {
            CultureInfo[] cultureInfos = CultureInfo.GetCultures(CultureTypes.NeutralCultures);
            foreach (CultureInfo cultureInfo in cultureInfos)
            {
                if (string.IsNullOrEmpty(cultureInfo.Name)) continue;
                if (!db.LitLanguageDbSet.Any(l => (l.Iso3 == cultureInfo.ThreeLetterISOLanguageName) && (l.Iso2 == cultureInfo.TwoLetterISOLanguageName)))
                {
                    LitLanguage lang = new LitLanguage()
                    {
                        Iso3 = cultureInfo.ThreeLetterISOLanguageName,
                        Iso2 = cultureInfo.TwoLetterISOLanguageName,
                        LanguageName = cultureInfo.EnglishName
                    };
                    db.LitLanguageDbSet.Add(lang);

                    db.SaveChanges();
                    db.Entry(lang).State = System.Data.Entity.EntityState.Detached;
                }
            }
        }
        public static void PopulateDialects(this LitDbContext db)
        {
            CultureInfo[] cultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures & CultureTypes.SpecificCultures);
            foreach (CultureInfo cultureInfo in cultureInfos)
            {
                if (string.IsNullOrEmpty(cultureInfo.Name)) continue;
                RegionInfo regionInfo = new RegionInfo(cultureInfo.Name);

                if (!db.LitLanguageDbSet.Any(l => (l.Iso3 == cultureInfo.ThreeLetterISOLanguageName) && (l.Iso2 == cultureInfo.TwoLetterISOLanguageName)))
                {
                    continue;
                }
                if (!db.LitCountryDbSet.Any(c => (c.Iso3 == regionInfo.ThreeLetterISORegionName) && (c.Iso2 == regionInfo.TwoLetterISORegionName)))
                {
                    continue;
                }
                if (db.LitDialectDbSet.Any(d => d.DialectId == cultureInfo.Name))
                {
                    continue;
                }
                if (!db.LitDialectDbSet.Any(d =>
                    (d.Iso3CntrRef == regionInfo.ThreeLetterISORegionName) && (d.Iso2CntrRef == regionInfo.TwoLetterISORegionName) &&
                    (d.Iso3LngRef == cultureInfo.ThreeLetterISOLanguageName) && (d.Iso2LngRef == cultureInfo.TwoLetterISOLanguageName)))
                {
                    LitDialect dialect = new LitDialect()
                    {
                        DialectId = cultureInfo.Name,

                        Iso3CntrRef = regionInfo.ThreeLetterISORegionName,
                        Iso2CntrRef = regionInfo.TwoLetterISORegionName,

                        Iso3LngRef = cultureInfo.ThreeLetterISOLanguageName,
                        Iso2LngRef = cultureInfo.TwoLetterISOLanguageName,

                        DialectName = cultureInfo.EnglishName
                    };
                    db.LitDialectDbSet.Add(dialect);
                    db.SaveChanges();
                    db.Entry(dialect).State = System.Data.Entity.EntityState.Detached;
                }
            }
        }
        public static void InsertGenger(this LitDbContext db, int GenreId, string GenreName)
        {
            if (!db.LitGenreDbSet.Any(l => (l.GenreName == GenreName)))
            {
                LitGenre genre = new LitGenre()
                {
                    GenreId = GenreId,
                    GenreName = GenreName
                };
                db.LitGenreDbSet.Add(genre);
                db.SaveChanges();
                db.Entry(genre).State = System.Data.Entity.EntityState.Detached;
            }
        }
        public static void PopulateGengers(this LitDbContext db)
        {
            db.InsertGenger(1, "Literary novel");
            db.InsertGenger(2, "Literary story");
            db.InsertGenger(3, "Literary essay");
            db.InsertGenger(4, "Literary poem");
            db.InsertGenger(5, "Literary short story");
            db.InsertGenger(6, "Literary play");

        }
        public static void InsertEdition(this LitDbContext db, int EditionId, string EditionName)
        {
            if (!db.LitEditionDbSet.Any(l => (l.EditionName == EditionName)))
            {
                LitEdition edition = new LitEdition()
                {
                    EditionId = EditionId,
                    EditionName = EditionName
                };
                db.LitEditionDbSet.Add(edition);
                db.SaveChanges();
                db.Entry(edition).State = System.Data.Entity.EntityState.Detached;
            }
        }
        public static void PopulateEditions(this LitDbContext db)
        {
            InsertEdition(db, 1, "First Edition");
            InsertEdition(db, 2, "Second Edition");
            InsertEdition(db, 3, "Third Edition");
            InsertEdition(db, 4, "Fourth Edition");
        }
    }

Having "DbHelpers"-class we add six additional lines of code

        Database.SetInitializer(new DropCreateDatabaseAlways<LitDbContext>());
        LitDbContext db = new LitDbContext();
        db.LitDialectDbSet.FirstOrDefault();
        MessageBox.Show("The database was successfully created.", "Done", 
            MessageBoxButton.OK, MessageBoxImage.Information);
        Database.SetInitializer(new CreateDatabaseIfNotExists<LitDbContext>());
// six lines have been added to the code
        db.PopulateCounties();
        db.PopulateLanguages();
        db.PopulateDialects();
        db.PopulateGengers();
        db.PopulateEditions();
        MessageBox.Show("The data was inserted.", "Done", MessageBoxButton.OK, MessageBoxImage.Information);

Console application execution throws the following exception:

System.Data.SqlClient.SqlException
  HResult=0x80131904

Message = Inserting the FOREIGN KEY constraint "FK_dbo.LitManuscripts_dbo.LitDialects_DialectIdRef" on the "LitManuscripts" table 
may result in loops or multiple cascading paths. 
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or change other FOREIGN KEY constraints.
Failed to create constraint or index.

To fix the issue:

  • open LitDbContext.cs-file of Dm02Context-project
  • goto "OnModelCreating(DbModelBuilder modelBuilder)"-method
  • modify "LitManuscript-to-Dialect" ForeigKey definition as follows:
    modelBuilder.Entity<LitManuscript>().HasRequired(d => d.Dialect)
    .WithMany(m => m.Manuscripts)
    .HasForeignKey(d => d.DialectIdRef).WillCascadeOnDelete(false);
 ".WillCascadeOnDelete(false)" added to the definition 
  • To Generate C# classes for the Manuscript View

    • Run Visual Studio and Open “WpfDemo” solution
    • Under ModelInterfacesClassLibrary-project create folder
      • Literature/LitManuscript
    • Right Click the folder
      • Literature/LitManuscript
    • And select “Wpf Forms Wizard” menu item to open the Wizard dialog
  • Note:

    • On the first page of the dialog the destination folder is shown. The destination folder is the folder in which the generated file will be saved.

picture

  • On the second page of the dialog the developer should select existing DbContext file. Select:
    • Dm02Context (project)
    • LitDbContext (context)

picture

- Click “Next”-button
  • On the third page of the dialog the developer should select the View. Select:
    • “LitManuscriptView“.
  • In the left panel select “UI List Properties” node and check "Shown" for all
  • With "Up" and "Down" buttons change the order of the fields
  • Check "New Line" as it is shown on the slide.

picture

  • In the left panel of the same page of the dialog select “UI Form Properties” node and check "Shown" for all properties.
  • With "Up" and "Down" buttons change the order of the fields as it is shown on the slide.
  • In the left panel of the same page of the dialog select “UI Form Properties” node and check "New Line" as it is shown on the slide.
  • Set “InputType” as it is shown on the slide.

picture

- Click “Next”-button
  • On the fourth page click “batch processing”-button. “Batch actions” dialog will be shown.
    • Select “01100-Intefaces.json”
    • Click “Start”-button

picture

- Close both dialogs
  • Under ModelServicesPrismModule-project create folder
    • Literature/LitManuscript
    • Right Click the folder
      • Literature/LitManuscript
    • And select “Wpf Forms Wizard” menu item to open the Wizard dialog
    • Repeat all the steps until the “Batch Actions” dialog box appears.
    • Note:
      • The developer should not define again
        • “UI List Properties”
        • “UI Form Properties”
      • All settings were saved during the first batch.
  • In “Batch actions” dialog
    • Select “01400-ApiService.json”
      • Click “Start”-button
    • Select “01420-SForm.json”
      • Click “Start”-button
    • Select “01500-Eform.json”
      • Click “Start”-button
    • Select “01600-Lform.json”
      • Click “Start”-button
    • Close both dialogs
  • Note #1:
    • Sform is a search form for the given View
    • Eform is an Edit form for the given View
    • Lform is a wrapper for the two forms above.
  • Note #2:
    • Sform and Eform are the basic forms with all the user interface logic for the given View.
    • Other forms are wrappers for these two.
  • Under ModelServicesPrismModule-project
    • open the file "Literature/LitManuscript/LitManuscriptViewService.cs" and follow the instruction at the beginning of the file:
/*
    In the file of IModule-class of the project for the current service the following lines of code must be inserted:
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            ...
            containerRegistry.Register<ILitManuscriptViewService, LitManuscriptViewService>();
            ...
        }
*/
  • Under ModelServicesPrismModule-project
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewSformViewModel.cs" and follow the instruction at the beginning of the file
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewSdlgViewModel.cs" and follow the instruction at the beginning of the file
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewEformViewModel.cs" and follow the instruction at the beginning of the file
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewEformViewModel.cs" and follow the instruction at the beginning of the file
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewLformViewModel.cs" and follow the instruction at the beginning of the file
    • open the file "Literature/LitManuscript/ViewModels/LitManuscriptViewLformViewModel.cs" and follow the instruction at the beginning of the file
  • Under ModelServicesPrismModule-project add the following lines of code into RegisterTypes()-method of the ModelServicesPrismModuleModule.cs
     // temporaty declaration for test only
            containerRegistry.RegisterForNavigation<LitManuscriptViewLformUserControl, LitManuscriptViewLformViewModel>("LitManuscriptViewLformUserControl");
  • Under ModelServicesPrismModule-project the RegisterTypes()-method of the ModelServicesPrismModuleModule.cs becomes as follows
        public void RegisterTypes(IContainerRegistry containerRegistry)
        {
            ...
            containerRegistry.Register<ILitManuscriptViewService, LitManuscriptViewService>();
            // According to requirements of the "LitManuscriptViewSformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            ViewModelLocationProvider.Register<LitManuscriptViewSformUserControl, LitManuscriptViewSformViewModel>();
            // According to requirements of the "LitManuscriptViewSformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.Register<UserControl, LitManuscriptViewSformUserControl>("LitManuscriptViewSformUserControl");
            // According to requirements of the "LitManuscriptViewSdlgViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.RegisterDialog<LitManuscriptViewSdlgUserControl, LitManuscriptViewSdlgViewModel>("LitManuscriptViewSdlgViewModel");
            // According to requirements of the "LitManuscriptViewEformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            ViewModelLocationProvider.Register<LitManuscriptViewEformUserControl, LitManuscriptViewEformViewModel>();
            // According to requirements of the "LitManuscriptViewEformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.Register<UserControl, LitManuscriptViewEformUserControl>("LitManuscriptViewEformUserControl");
            // According to requirements of the "LitManuscriptViewEdlgViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.RegisterDialog<LitManuscriptViewEdlgUserControl, LitManuscriptViewEdlgViewModel>("LitManuscriptViewEdlgViewModel");
            // According to requirements of the "LitManuscriptViewLformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            ViewModelLocationProvider.Register<LitManuscriptViewLformUserControl, LitManuscriptViewLformViewModel>();
            // According to requirements of the "LitManuscriptViewLformViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.Register<UserControl, LitManuscriptViewLformUserControl>("LitManuscriptViewLformUserControl");
            // According to requirements of the "LitManuscriptViewLdlgViewModel.cs"-file of "ModelServicesPrismModule"-project. 
            containerRegistry.RegisterDialog<LitManuscriptViewLdlgUserControl, LitManuscriptViewLdlgViewModel>("LitManuscriptViewLdlgViewModel");


            // temporaty declaration for test only
            containerRegistry.RegisterForNavigation<LitGenreViewLformUserControl, LitGenreViewLformViewModel>("LitGenreViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitEditionViewLformUserControl, LitEditionViewLformViewModel>("LitEditionViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitCountryViewLformUserControl, LitCountryViewLformViewModel>("LitCountryViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitLanguageViewLformUserControl, LitLanguageViewLformViewModel>("LitLanguageViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitDialectViewLformUserControl, LitDialectViewLformViewModel>("LitDialectViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitPublisherViewLformUserControl, LitPublisherViewLformViewModel>("LitPublisherViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitAuthorViewLformUserControl, LitAuthorViewLformViewModel>("LitAuthorViewLformUserControl");
            containerRegistry.RegisterForNavigation<LitManuscriptViewLformUserControl, LitManuscriptViewLformViewModel>("LitManuscriptViewLformUserControl");
        }

  • Open "ViewModels\MainWindowViewModel.cs"-file of the PrismDemoApp-project
  • Modify _MainMenu variable as shown
IEnumerable<IWebServiceFilterMenuInterface> _MainMenu = new ObservableCollection<IWebServiceFilterMenuInterface>()
{
  new WebServiceFilterMenuViewModel() { Id = "000", Caption="Home", IconName="Home",  IconColor="Primary", Data="HomeUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="LitGenre Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitGenreViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="LitEdition Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitEditionViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="Country Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitCountryViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="Language Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitLanguageViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="Dialect Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitDialectViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="Publisher Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitPublisherViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
  new WebServiceFilterMenuViewModel() { Id = "001", Caption="Manuscript Lform", IconName="TableRefresh",  IconColor="Primary", Data="LitManuscriptViewLformUserControl", Command=RoutedCommandExt.MainMenuCommand},
};
  • rebuild
    • ModelInterfacesClassLibrary
    • ModelServicesPrismModule
    • PrismDemoApp
  • run Dm04WebApp
  • run PrismDemoApp
  • At first: in the app click "Author Lform"-menu item and add a pair of records
  • At second: In the app click "Manuscript Lform"-menu item and add a pair of records

picture