SlideShare une entreprise Scribd logo
1  sur  51
Prism 4.1 With MEF


        Rainer Stropek
time cockpit (http://www.timecockpit.com)
Introduction
• software architects gmbh
• Rainer Stropek
   – Developer, Speaker, Trainer
   – MVP for Windows Azure
     since 2010
   – rainer@timecockpit.com
   –         @rstropek



                                   http://www.timecockpit.com
                                   http://www.timecockpit.com/devblog
Download Code Sample
http://bit.ly/WPFPrismTraining
Applies to all
open customers

         Applies to active
            customer
                                              Sample
                                                             Main Menu
                             Controls views




                                                                         Detail region




                                              CustomerList
                                                 region
Sample – Resources
• Download Prism (optional)
• Add Prism NuGet Package to solution
Initialization
Bootstrapper
• Setup module catalog
• Setup dependency injection container
       – Here: MEF
• Create the shell

• Call bootstrapper in WPF application startup routine
   using System.Windows;

   namespace PrismDemoApp
   {
     public partial class App : Application
     {
        protected override void OnStartup(StartupEventArgs e)
        {
          base.OnStartup(e);

               var bootstrapper = new Bootstrapper();
               bootstrapper.Run();
           }
       }
   }
Setup Module Catalog
• Bootstrapper.CreateModuleCatalog
     – Default: Create empty ModuleCatalog
     – Override it to create your custom instance of IModuleCatalog
•   Create module catalog
     – In Code
       ModuleCatalog.AddModule
     – From XAML
       ModuleCatalog.CreateFromXaml
     – From app.config
       Override CreateModuleCatalog as follows:

    <modules>
       <module assemblyFile="[…].dll" moduleType="[…]" moduleName="[…]" startupLoaded="false" />
       <module assemblyFile="[…].dll" moduleType="[…]" moduleName="[…]" startupLoaded="false">
         <dependencies>
           <dependency moduleName="[…]"/>
         </dependencies>
       </module>
     </modules>
Setup Dependency Injection
• Prism standard services:
Setup Dependency Injection (MEF)

• Optional
   – Override CreateContainer and ConfigureContainer
   – Make sure to call base class' implementation to get standard
     services
     protected override void ConfigureContainer()
     {
       base.ConfigureContainer();

         // Publish container using MEF
         this.Container.ComposeExportedValue<CompositionContainer>(this.Container);
     }




• Override ConfigureAggregateCatalog
   – Example:
     protected override void ConfigureAggregateCatalog()
     {
       base.ConfigureAggregateCatalog();
       this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Shell).Assembly));
     }
Create Shell (MEF)
• Create and initialize the shell
  protected override DependencyObject CreateShell()
  {
    return this.Container.GetExportedValue<Shell>();
  }

  protected override void InitializeShell()
  {
    Application.Current.MainWindow = this.Shell as Window;
    Application.Current.MainWindow.Show();
  }
Sample: Bootstrapper
using   Microsoft.Practices.Prism.MefExtensions;
using   System.ComponentModel.Composition;
using   System.ComponentModel.Composition.Hosting;
using   System.IO;
using   System.Reflection;
using   System.Windows;

namespace Prism41Sample.UI
{
    public class Bootstrapper : MefBootstrapper
    {
        /// <summary>
        /// Sets up MEF catalogs
        /// </summary>
        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();

              var executingAssembly = Assembly.GetExecutingAssembly();
              // Use current assembly when looking for MEF exports
              this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(executingAssembly));
              // Look into "Modules" directory to dynamically load additional exports
              this.AggregateCatalog.Catalogs.Add(new DirectoryCatalog(
                  Path.Combine(Path.GetDirectoryName(executingAssembly.Location),
                      "RuntimeModules")));
          }
Sample: Bootstrapper
        /// <summary>
        /// Exports MEF container in service locator
        /// </summary>
        protected override CompositionContainer CreateContainer()
        {
            var container = base.CreateContainer();
            container.ComposeExportedValue(container);
            return container;
        }

        protected override DependencyObject CreateShell()
        {
            // Create a new instance of the applications "MainWindow"
            return this.Container.GetExportedValue<Window>("MainWindow");
        }

        /// <summary>
        /// Makes shell the main window of the application.
        /// </summary>
        protected override void InitializeShell()
        {
            base.InitializeShell();

            Application.Current.MainWindow = this.Shell as Window;
            Application.Current.MainWindow.Show();
        }
    }
}
Sample: Bootstrapper
using Prism41Sample.UI.ViewModel;
using System.ComponentModel.Composition;
using System.Windows;

namespace Prism41Sample.UI.View
{
    [Export("MainWindow", typeof(Window))]
    public partial class MainWindow : Window
    {
        [ImportingConstructor]
        public MainWindow(MainWindowViewModel viewModel)
        {
            InitializeComponent();
            this.DataContext = viewModel;
        }
    }
}
Modules
Module Creation (1/2)
• Implement IModule
• Register named modules in XAML, app.config, or
  code (see above)
• Declarative metadata attributes for modules
  [ModuleExport(typeof(DataManagementModule), InitializationMode = InitializationMode.WhenAvailable)]
  public class DataManagementModule : IModule
  {
    public void Initialize()
    {
       […]
    }

      […]
  }



• Dependency management (incl. cycle detection)
  [ModuleExport(typeof(ModuleA), DependsOnModuleNames = new string[] { "ModuleD" })]
  public class ModuleA : IModule
  {
    […]
  }
Module Creation (2/2)
• Load modules from directory with
  DirectoryModuleCatalog
  protected override IModuleCatalog CreateModuleCatalog()
  {
      return new DirectoryModuleCatalog() {ModulePath = @".Modules"};
  }




• Load modules from directory with MEF
  protected override void ConfigureAggregateCatalog()
  {
      base.ConfigureAggregateCatalog();

      DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules");
      this.AggregateCatalog.Catalogs.Add(catalog);
  }
Sample: Repository Module
using   Microsoft.Practices.Prism.MefExtensions.Modularity;
using   Microsoft.Practices.Prism.Modularity;
using   Microsoft.Practices.ServiceLocation;
using   Prism41Sample.Infrastructure;
using   System.ComponentModel.Composition;
using   System.ComponentModel.Composition.Hosting;

namespace Prism41Sample.Repository
{
    [ModuleExport("RepositoryModule", typeof(RepositoryModule))]
    public class RepositoryModule : IModule
    {
        [Import]
        private IServiceLocator serviceLocator = null;

          public void Initialize()
          {
              // Publish repository service using MEF
              var container = this.serviceLocator.GetInstance<CompositionContainer>();
              container.ComposeExportedValue<RepositoryBase>(new CustomerRepository());
          }
    }
}
UI Composition
Regions and Views
Regions and Views
Region Adapters
• ContentControlRegionAdapter
• SelectorRegionAdapter
 – E.g. TabControl
• ItemsControlRegionAdapter
 – E.g. ListBox
Defining Regions
• In XAML
 <UserControl […]
   xmlns:prism="http://www.codeplex.com/prism">
   […]
   <Controls:AnimatedTabControl
      x:Name="PositionBuySellTab"
      prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/>
   […]
 </UserControl>




• In Code
 IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
 RegionManager.SetRegionManager(this.ActionContent, regionManager);
 RegionManager.SetRegionName(this.ActionContent, "ActionRegion");
Defining Regions
• In XAML
 <UserControl […]
   xmlns:prism="http://www.codeplex.com/prism">
   […]
   <Controls:AnimatedTabControl
      x:Name="PositionBuySellTab"
      prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/>
   […]
 </UserControl>




• In Code
 IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
 RegionManager.SetRegionManager(this.ActionContent, regionManager);
 RegionManager.SetRegionName(this.ActionContent, "ActionRegion");
Loading Content Into Regions




// View discovery using composition container
this.regionManager.RegisterViewWithRegion("MainRegion", typeof(EmployeeView));
// …or delegate
this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<EmployeeView>());


// Add view in code
IRegion region = regionManager.Regions["MainRegion"];
var ordersView = container.Resolve<OrdersView>();
region.Add(ordersView, "OrdersView");
Tips For Views and Regions
• Ordering of views in a region
  [Export]
  [ViewSortHint("01")]
  public partial class EmailNavigationItemView

  [Export]
  [ViewSortHint("02")]
  public partial class CalendarNavigationItemView




• Sharing data between regions
   – Attached property RegionContext
  <TabControl AutomationProperties.AutomationId="DetailsTabControl"
    cal:RegionManager.RegionName="{x:Static local:RegionNames.TabRegion}"
    cal:RegionManager.RegionContext="{Binding Path=SelectedEmployee.EmployeeId}"
    ...>


  // Read value of RegionContext
  private void GetRegionContext()
  {
    this.Model.EmployeeId = (int)RegionContext.GetObservableContext(this).Value;
  }
Sample: Defining Regions
 <!-- Overview -->
<ContentControl Grid.Row="1" prism:RegionManager.RegionName=
    "{x:Static inf:RegionAndModuleStringConstants.OverviewRegionName}" />

<GridSplitter Grid.Row="1" Style="{StaticResource VerticalGridSplitter}" />

<!-- Details -->
<ContentControl Grid.Row="1" Grid.RowSpan="2" Grid.Column="1"
    prism:RegionManager.RegionName=
        "{x:Static inf:RegionAndModuleStringConstants.DetailRegionName}" />



                                           Tip: Remove magic strings
                                               using static classes
Sample: Defining Regions
 <!-- Overview -->
<ContentControl Grid.Row="1" prism:RegionManager.RegionName=
    "{x:Static inf:RegionAndModuleStringConstants.OverviewRegionName}" />

<GridSplitter Grid.Row="1" Style="{StaticResource VerticalGridSplitter}" />

<!-- Details -->
<TabControl Grid.Row="1" Grid.RowSpan="2" Grid.Column="1"
    prism:RegionManager.RegionName=
        "{x:Static inf:RegionAndModuleStringConstants.DetailRegionName}">



Note different behavior if
region is an items control
Sample
                              Event
                            Aggregator




ActivateCustomer(11)




                       Register customer list
                       view to appear in this
                               region
Sample: UI Module
namespace Prism41Sample.CustomerMaintenance
{
    [ModuleExport("CustomerMaintenanceModule", typeof(CustomerMaintenanceModule),
        DependsOnModuleNames = new[] { "RepositoryModule" })]
    public class CustomerMaintenanceModule : IModule
    {
        [Import]
        private IServiceLocator serviceLocator = null;

        [Import]
        private IRegionManager regionManager = null;

        public void Initialize()
        {
            regionManager.RegisterViewWithRegion(
                RegionAndModuleStringConstants.OverviewRegionName,
                () => this.serviceLocator.GetInstance<CustomerList>());
        }
    }
}
Sample: Event Aggregator
[Import]
private IEventAggregator eventAggregator = null;

private Customer SelectedCustomerValue = default(Customer);
public Customer SelectedCustomer
{
    get { return this.SelectedCustomerValue; }
    set
    {
        if (this.SelectedCustomerValue != value)
        {
            this.SelectedCustomerValue = value;
            this.RaisePropertyChanged(() => this.SelectedCustomer);
            this.eventAggregator.GetEvent<ActivateCustomerEvent>()
                .Publish(this.SelectedCustomer.CustomerNumber);
        }
    }
}
Sample: Event Aggregator
using   Microsoft.Practices.Prism.Events;
using   System;
using   System.Collections.Generic;
using   System.Linq;
using   System.Text;
using   System.Threading.Tasks;

namespace Prism41Sample.CustomerMaintenance
{
    public class ActivateCustomerEvent : CompositePresentationEvent<int>
    {
    }
}
Navigation
Navigation
• Basic navigation
  IRegion mainRegion = ...;
  mainRegion.RequestNavigate(new Uri("InboxView", UriKind.Relative));

  // or
  IRegionManager regionManager = ...;
  regionManager.RequestNavigate("MainRegion",
                                 new Uri("InboxView", UriKind.Relative));




• Prerequisite (for MEF): Export of the view
  [Export("InboxView")]
  public partial class InboxView : UserControl



• Parameters for navigation
  Employee employee = Employees.CurrentItem as Employee;
  if (employee != null)
  {
      UriQuery query = new UriQuery();
      query.Add("ID", employee.Id);
      _regionManager.RequestNavigate(RegionNames.TabRegion,
           new Uri("EmployeeDetailsView" + query.ToString(), UriKind.Relative));
  }
Sample: Event Aggregator
[Export]
public class MainWindowViewModel : NotificationObject
{
    private IEventAggregator eventAggregator = null;

   [Import]
   private IRegionManager regionManager = null;

   [ImportingConstructor]
   public MainWindowViewModel(IEventAggregator eventAggregator)
   {
       this.eventAggregator = eventAggregator;
       this.eventAggregator.GetEvent<ActivateCustomerEvent>().Subscribe(this.OnActivateCustomer);
   }

   #region Main window controller
   // You should implement the controller in a separate class if navigation is more complex.

   private void OnActivateCustomer(int customerNumber)
   {
       var q = new UriQuery();
       q.Add("CustomerNumber", customerNumber.ToString());
       this.regionManager.RequestNavigate(
           RegionAndModuleStringConstants.DetailRegionName,
           new Uri("CustomerDetail" + q.ToString(), UriKind.Relative));
   }
   #endregion
MVVM Commands
Command Objects
• Implement ICommand yourself
• Use Prism's DelegateCommand<T>
 public class DelegateCommand<T> : DelegateCommandBase
 {
     public DelegateCommand(
        Action<T> executeMethod,
        Func<T,bool> canExecuteMethod )
      : base((o) => executeMethod((T)o), (o) => canExecuteMethod((T)o))
     {
         ...
     }
 }
Sample: Delegate Command
public class MainWindowViewModel : NotificationObject
{
    [ImportingConstructor]
    public MainWindowViewModel(IEventAggregator eventAggregator)
    {
        this.CloseAllTabsCommand = new DelegateCommand(this.OnCloseAllTabs);
        …
    }
    public ICommand CloseAllTabsCommand { get; private set; }

    private void OnCloseAllTabs()
    {
        var detailRegion = this.regionManager.Regions[
            RegionAndModuleStringConstants.DetailRegionName];
        foreach (var view in detailRegion.Views)
        {
            // if the view implements IDisposable, call Dispose on it
            var disposableView = view as IDisposable;
            if (disposableView != null)
            {
                disposableView.Dispose();
            }

            detailRegion.Remove(view);
        }
    }
    …
}
Command Objects With
                  Interaction Triggers
•   Use commands with controls that does not support commands out of
    the box
•   Defined in Expression Blend
     – Tip: Reference assemblies come with Prism
•   Example:
    <UserControl […]
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
      xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
      […]
      <TextBlock Margin="5" Text="Hello World!">
         <i:Interaction.Triggers>
           <i:EventTrigger EventName="MouseLeftButtonDown">
              <i:InvokeCommandAction Command="{Binding Path=MyCommand}"/>
           </i:EventTrigger>
         </i:Interaction.Triggers>
      </TextBlock>
      […]
    </UserControl>



•   Use CallMethodAction to call methods without ICommand
     – No support for parameters
Composite Commands (1/2)
• Implemented in CompositeCommand
  – RegisterCommand
  – UnregisterCommand




    Source: Prism 4 documentation (Microsoft)
Composite Commands (2/2)




•   Implement IActiveAware on View or ViewModel class
•   Implement IActiveAware on your commands
     – DelegateCommand and CompositeCommand already implement
       IActiveAware
•   When View/ViewModel becomes inactive, deactivate child commands
•   Specify true in monitorCommandActivity of constructor of
    CompositeCommand
Interaction Services (WPF)
• ViewModel communicates with View using an
  interaction service
   var result =
       interactionService.ShowMessageBox(
           "Are you sure you want to cancel this operation?",
           "Confirm",
           MessageBoxButton.OK );
   if (result == MessageBoxResult.Yes)
   {
       CancelRequest();
   }




• Note: Silverlight not covered here
Sample: Composite Commands
namespace Prism41Sample.UI.ViewModel
{
    [Export(typeof(IGlobalCommands))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class GlobalCommands : IGlobalCommands
    {
        public GlobalCommands()
        {
            this.SaveAllCommand = new CompositeCommand();
            this.PrintActiveItem = new CompositeCommand(true);
        }

       public CompositeCommand SaveAllCommand { get; private set; }
       public CompositeCommand PrintActiveItem { get; private set; }
Sample: Composite Commands
        #region IGlobalCommands implementation
        public void RegisterSaveAllCommand(ICommand subCommand)
        {
            this.SaveAllCommand.RegisterCommand(subCommand);
        }

        public void RegisterPrintActiveItemCommand(ICommand subCommand)
        {
            this.PrintActiveItem.RegisterCommand(subCommand);
        }



        public void UnregisterSaveAllCommand(ICommand subCommand)
        {
            this.SaveAllCommand.UnregisterCommand(subCommand);
        }

        public void UnregisterPrintActiveItemCommand(
            ICommand subCommand)
        {
            this.PrintActiveItem.UnregisterCommand(subCommand);
        }
        #endregion
    }
}
Sample: Composite Commands
namespace Prism41Sample.CustomerMaintenance.ViewModel
{
    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class CustomerDetailViewModel : NotificationObject, ITitledViewModel,
                                           INavigationAware, IActiveAware, IDisposable
    {
        private RepositoryBase repository = null;
        private IGlobalCommands globalCommands;
        private DelegateCommand saveAllCommand;
        private DelegateCommand printCommand;

       [ImportingConstructor]
       public CustomerDetailViewModel(RepositoryBase repository, IGlobalCommands globalCommands)
       {
           this.repository = repository;
           this.globalCommands = globalCommands;

           this.globalCommands.RegisterSaveAllCommand(
               this.saveAllCommand = new DelegateCommand(
                   () => Debug.WriteLine(
                       "Saving Customer {0}", this.SelectedCustomer.CustomerNumber)));
           this.globalCommands.RegisterPrintActiveItemCommand(
               this.printCommand = new DelegateCommand(
                   () => Debug.WriteLine(
                       "Printing Customer {0}", this.SelectedCustomer.CustomerNumber)));
       }
Sample: Composite Commands
   ~CustomerDetailViewModel()
   {
       this.Dispose(false);
   }

   private Customer SelectedCustomerValue = default(Customer);
   public Customer SelectedCustomer
   {
       get { return this.SelectedCustomerValue; }
       set
       {
           if (this.SelectedCustomerValue != value)
           {
               this.SelectedCustomerValue = value;
               this.RaisePropertyChanged(() => this.SelectedCustomer);
           }
       }
   }
Sample: Composite Commands
   public bool IsNavigationTarget(NavigationContext navigationContext)
   {
       return this.GetCustomerNumberFromParameters(navigationContext) ==
           this.SelectedCustomer.CustomerNumber;
   }

   public void OnNavigatedFrom(NavigationContext navigationContext)
   {
   }

   public void OnNavigatedTo(NavigationContext navigationContext)
   {
       this.SelectedCustomer = this.repository
           .Customers
           .Where(c => c.CustomerNumber
                == this.GetCustomerNumberFromParameters(navigationContext))
           .FirstOrDefault();
   }

   private int GetCustomerNumberFromParameters(NavigationContext navigationContext)
   {
       return Int32.Parse(navigationContext.Parameters["CustomerNumber"]);
   }
Sample: Composite Commands
   private bool IsActiveValue = default(bool);
   public bool IsActive
   {
       get { return this.IsActiveValue; }
       set
       {
           if (this.IsActiveValue != value)
           {
               this.IsActiveValue = value;
               this.printCommand.IsActive = this.IsActive;
               this.RaisePropertyChanged(() => this.IsActive);
               if (this.IsActiveChanged != null)
               {
                   this.IsActiveChanged(this, new EventArgs());
               }
           }
       }
   }

   public event EventHandler IsActiveChanged;
Sample: Composite Commands
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.globalCommands.UnregisterSaveAllCommand(this.saveAllCommand);
                this.globalCommands.UnregisterPrintActiveItemCommand(this.printCommand);
            }
        }
    }
}
Q&A
          Thank you for your attention!



Rainer Stropek
software architects
rainer@timecockpit.com
http://www.timecockpit.com
is the leading time tracking solution for knowledge
workers. Graphical time tracking calendar, automatic tracking of
your work using signal trackers, high level of extensibility and
customizability, full support to work offline, and SaaS
deployment model make it the optimal choice especially in the
IT consulting business.

Try                 for free and without any risk. You can get your
trial account at http://www.timecockpit.com. After the trial
period you can use                  for only 0,20€ per user and
month without a minimal subscription time and without a
minimal number of users.
ist die führende Projektzeiterfassung für
Knowledge Worker. Grafischer Zeitbuchungskalender,
automatische Tätigkeitsaufzeichnung über Signal Tracker,
umfassende Erweiterbarkeit und Anpassbarkeit, volle
Offlinefähigkeit und einfachste Verwendung durch SaaS machen
es zur Optimalen Lösung auch speziell im IT-Umfeld.

Probieren Sie              kostenlos und ohne Risko einfach
aus. Einen Testzugang erhalten Sie unter http://www.timecockpit.com.
Danach nutzen Sie               um nur 0,20€ pro Benutzer und
Tag ohne Mindestdauer und ohne Mindestbenutzeranzahl.

Contenu connexe

Tendances

Tendances (20)

How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
Advance JS and oop
Advance JS and oopAdvance JS and oop
Advance JS and oop
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
 
Smart Migration to JDK 8
Smart Migration to JDK 8Smart Migration to JDK 8
Smart Migration to JDK 8
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling Rewriter
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
New Features Of JDK 7
New Features Of JDK 7New Features Of JDK 7
New Features Of JDK 7
 
Java RMI
Java RMIJava RMI
Java RMI
 
Hibernate
Hibernate Hibernate
Hibernate
 
Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams
 
Codegeneration With Xtend
Codegeneration With XtendCodegeneration With Xtend
Codegeneration With Xtend
 
Open erp technical_memento_v0.6.3_a4
Open erp technical_memento_v0.6.3_a4Open erp technical_memento_v0.6.3_a4
Open erp technical_memento_v0.6.3_a4
 
Intro to JavaScript
Intro to JavaScriptIntro to JavaScript
Intro to JavaScript
 
Java 8 features
Java 8 featuresJava 8 features
Java 8 features
 
Java 5 and 6 New Features
Java 5 and 6 New FeaturesJava 5 and 6 New Features
Java 5 and 6 New Features
 
Modern Programming in Java 8 - Lambdas, Streams and Date Time API
Modern Programming in Java 8 - Lambdas, Streams and Date Time APIModern Programming in Java 8 - Lambdas, Streams and Date Time API
Modern Programming in Java 8 - Lambdas, Streams and Date Time API
 
Java 8 Features
Java 8 FeaturesJava 8 Features
Java 8 Features
 
Getting started with Java 9 modules
Getting started with Java 9 modulesGetting started with Java 9 modules
Getting started with Java 9 modules
 

En vedette

Michael Kiener Associates Ltd
Michael Kiener Associates LtdMichael Kiener Associates Ltd
Michael Kiener Associates Ltd
MichaelKiener
 

En vedette (12)

P/Invoke - Interoperability of C++ and C#
P/Invoke - Interoperability of C++ and C#P/Invoke - Interoperability of C++ and C#
P/Invoke - Interoperability of C++ and C#
 
Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...
Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...
Coding Like the Wind - Tips and Tricks for the Microsoft Visual Studio 2012 C...
 
Agile and Scrum Workshop
Agile and Scrum WorkshopAgile and Scrum Workshop
Agile and Scrum Workshop
 
Whats New in Visual Studio 2012 for C++ Developers
Whats New in Visual Studio 2012 for C++ DevelopersWhats New in Visual Studio 2012 for C++ Developers
Whats New in Visual Studio 2012 for C++ Developers
 
SaaS, Multi-Tenancy and Cloud Computing
SaaS, Multi-Tenancy and Cloud ComputingSaaS, Multi-Tenancy and Cloud Computing
SaaS, Multi-Tenancy and Cloud Computing
 
Business Model Evolution - Why The Journey To SaaS Makes Sense
Business Model Evolution - Why The Journey To SaaS Makes SenseBusiness Model Evolution - Why The Journey To SaaS Makes Sense
Business Model Evolution - Why The Journey To SaaS Makes Sense
 
Programming With WinRT And Windows8
Programming With WinRT And Windows8Programming With WinRT And Windows8
Programming With WinRT And Windows8
 
Vertaalbureau Perfect
Vertaalbureau PerfectVertaalbureau Perfect
Vertaalbureau Perfect
 
Michael Kiener Associates Ltd
Michael Kiener Associates LtdMichael Kiener Associates Ltd
Michael Kiener Associates Ltd
 
Telerik Kendo UI vs. AngularJS
Telerik Kendo UI vs. AngularJSTelerik Kendo UI vs. AngularJS
Telerik Kendo UI vs. AngularJS
 
Sculptura in coaja de ou
Sculptura in coaja de ouSculptura in coaja de ou
Sculptura in coaja de ou
 
Cloud computing was bringt's
Cloud computing   was bringt'sCloud computing   was bringt's
Cloud computing was bringt's
 

Similaire à WPF and Prism 4.1 Workshop at BASTA Austria

Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)
Oro Inc.
 
Spring Live Sample Chapter
Spring Live Sample ChapterSpring Live Sample Chapter
Spring Live Sample Chapter
Syed Shahul
 
Apache DeltaSpike
Apache DeltaSpikeApache DeltaSpike
Apache DeltaSpike
os890
 

Similaire à WPF and Prism 4.1 Workshop at BASTA Austria (20)

Sencha ExtJs Learning Part 2 - MVC And MVVM Architecture in ExtJs [ENGLISH]
Sencha ExtJs Learning Part 2 - MVC And MVVM Architecture in ExtJs [ENGLISH]Sencha ExtJs Learning Part 2 - MVC And MVVM Architecture in ExtJs [ENGLISH]
Sencha ExtJs Learning Part 2 - MVC And MVVM Architecture in ExtJs [ENGLISH]
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO Extended
 
Symfony2 - from the trenches
Symfony2 - from the trenchesSymfony2 - from the trenches
Symfony2 - from the trenches
 
Angular 2 for Java Developers
Angular 2 for Java DevelopersAngular 2 for Java Developers
Angular 2 for Java Developers
 
Symfony2 from the Trenches
Symfony2 from the TrenchesSymfony2 from the Trenches
Symfony2 from the Trenches
 
Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)
 
Android Meetup Slovenija #3 - Testing with Robolectric by Ivan Kust
Android Meetup Slovenija #3 - Testing with Robolectric by Ivan KustAndroid Meetup Slovenija #3 - Testing with Robolectric by Ivan Kust
Android Meetup Slovenija #3 - Testing with Robolectric by Ivan Kust
 
Meteor
MeteorMeteor
Meteor
 
Front end development with Angular JS
Front end development with Angular JSFront end development with Angular JS
Front end development with Angular JS
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
Workshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testingWorkshop 23: ReactJS, React & Redux testing
Workshop 23: ReactJS, React & Redux testing
 
Spring Live Sample Chapter
Spring Live Sample ChapterSpring Live Sample Chapter
Spring Live Sample Chapter
 
Multi Client Development with Spring
Multi Client Development with SpringMulti Client Development with Spring
Multi Client Development with Spring
 
Modernize Your Real-World Application with Eclipse 4 and JavaFX
Modernize Your Real-World Application with Eclipse 4 and JavaFXModernize Your Real-World Application with Eclipse 4 and JavaFX
Modernize Your Real-World Application with Eclipse 4 and JavaFX
 
From Zero to Cloud in 12 Easy Factors
From Zero to Cloud in 12 Easy FactorsFrom Zero to Cloud in 12 Easy Factors
From Zero to Cloud in 12 Easy Factors
 
Developing maintainable Cordova applications
Developing maintainable Cordova applicationsDeveloping maintainable Cordova applications
Developing maintainable Cordova applications
 
Testing your application on Google App Engine
Testing your application on Google App EngineTesting your application on Google App Engine
Testing your application on Google App Engine
 
Testing Your Application On Google App Engine
Testing Your Application On Google App EngineTesting Your Application On Google App Engine
Testing Your Application On Google App Engine
 
Liferay (DXP) 7 Tech Meetup for Developers
Liferay (DXP) 7 Tech Meetup for DevelopersLiferay (DXP) 7 Tech Meetup for Developers
Liferay (DXP) 7 Tech Meetup for Developers
 
Apache DeltaSpike
Apache DeltaSpikeApache DeltaSpike
Apache DeltaSpike
 

Dernier

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Dernier (20)

Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024Top 10 Most Downloaded Games on Play Store in 2024
Top 10 Most Downloaded Games on Play Store in 2024
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 

WPF and Prism 4.1 Workshop at BASTA Austria

  • 1. Prism 4.1 With MEF Rainer Stropek time cockpit (http://www.timecockpit.com)
  • 2. Introduction • software architects gmbh • Rainer Stropek – Developer, Speaker, Trainer – MVP for Windows Azure since 2010 – rainer@timecockpit.com – @rstropek http://www.timecockpit.com http://www.timecockpit.com/devblog
  • 4. Applies to all open customers Applies to active customer Sample Main Menu Controls views Detail region CustomerList region
  • 5. Sample – Resources • Download Prism (optional) • Add Prism NuGet Package to solution
  • 7. Bootstrapper • Setup module catalog • Setup dependency injection container – Here: MEF • Create the shell • Call bootstrapper in WPF application startup routine using System.Windows; namespace PrismDemoApp { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var bootstrapper = new Bootstrapper(); bootstrapper.Run(); } } }
  • 8. Setup Module Catalog • Bootstrapper.CreateModuleCatalog – Default: Create empty ModuleCatalog – Override it to create your custom instance of IModuleCatalog • Create module catalog – In Code ModuleCatalog.AddModule – From XAML ModuleCatalog.CreateFromXaml – From app.config Override CreateModuleCatalog as follows: <modules> <module assemblyFile="[…].dll" moduleType="[…]" moduleName="[…]" startupLoaded="false" /> <module assemblyFile="[…].dll" moduleType="[…]" moduleName="[…]" startupLoaded="false"> <dependencies> <dependency moduleName="[…]"/> </dependencies> </module> </modules>
  • 9. Setup Dependency Injection • Prism standard services:
  • 10. Setup Dependency Injection (MEF) • Optional – Override CreateContainer and ConfigureContainer – Make sure to call base class' implementation to get standard services protected override void ConfigureContainer() { base.ConfigureContainer(); // Publish container using MEF this.Container.ComposeExportedValue<CompositionContainer>(this.Container); } • Override ConfigureAggregateCatalog – Example: protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Shell).Assembly)); }
  • 11. Create Shell (MEF) • Create and initialize the shell protected override DependencyObject CreateShell() { return this.Container.GetExportedValue<Shell>(); } protected override void InitializeShell() { Application.Current.MainWindow = this.Shell as Window; Application.Current.MainWindow.Show(); }
  • 12. Sample: Bootstrapper using Microsoft.Practices.Prism.MefExtensions; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; using System.IO; using System.Reflection; using System.Windows; namespace Prism41Sample.UI { public class Bootstrapper : MefBootstrapper { /// <summary> /// Sets up MEF catalogs /// </summary> protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); var executingAssembly = Assembly.GetExecutingAssembly(); // Use current assembly when looking for MEF exports this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(executingAssembly)); // Look into "Modules" directory to dynamically load additional exports this.AggregateCatalog.Catalogs.Add(new DirectoryCatalog( Path.Combine(Path.GetDirectoryName(executingAssembly.Location), "RuntimeModules"))); }
  • 13. Sample: Bootstrapper /// <summary> /// Exports MEF container in service locator /// </summary> protected override CompositionContainer CreateContainer() { var container = base.CreateContainer(); container.ComposeExportedValue(container); return container; } protected override DependencyObject CreateShell() { // Create a new instance of the applications "MainWindow" return this.Container.GetExportedValue<Window>("MainWindow"); } /// <summary> /// Makes shell the main window of the application. /// </summary> protected override void InitializeShell() { base.InitializeShell(); Application.Current.MainWindow = this.Shell as Window; Application.Current.MainWindow.Show(); } } }
  • 14. Sample: Bootstrapper using Prism41Sample.UI.ViewModel; using System.ComponentModel.Composition; using System.Windows; namespace Prism41Sample.UI.View { [Export("MainWindow", typeof(Window))] public partial class MainWindow : Window { [ImportingConstructor] public MainWindow(MainWindowViewModel viewModel) { InitializeComponent(); this.DataContext = viewModel; } } }
  • 16. Module Creation (1/2) • Implement IModule • Register named modules in XAML, app.config, or code (see above) • Declarative metadata attributes for modules [ModuleExport(typeof(DataManagementModule), InitializationMode = InitializationMode.WhenAvailable)] public class DataManagementModule : IModule { public void Initialize() { […] } […] } • Dependency management (incl. cycle detection) [ModuleExport(typeof(ModuleA), DependsOnModuleNames = new string[] { "ModuleD" })] public class ModuleA : IModule { […] }
  • 17. Module Creation (2/2) • Load modules from directory with DirectoryModuleCatalog protected override IModuleCatalog CreateModuleCatalog() { return new DirectoryModuleCatalog() {ModulePath = @".Modules"}; } • Load modules from directory with MEF protected override void ConfigureAggregateCatalog() { base.ConfigureAggregateCatalog(); DirectoryCatalog catalog = new DirectoryCatalog("DirectoryModules"); this.AggregateCatalog.Catalogs.Add(catalog); }
  • 18. Sample: Repository Module using Microsoft.Practices.Prism.MefExtensions.Modularity; using Microsoft.Practices.Prism.Modularity; using Microsoft.Practices.ServiceLocation; using Prism41Sample.Infrastructure; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace Prism41Sample.Repository { [ModuleExport("RepositoryModule", typeof(RepositoryModule))] public class RepositoryModule : IModule { [Import] private IServiceLocator serviceLocator = null; public void Initialize() { // Publish repository service using MEF var container = this.serviceLocator.GetInstance<CompositionContainer>(); container.ComposeExportedValue<RepositoryBase>(new CustomerRepository()); } } }
  • 21. Regions and Views Region Adapters • ContentControlRegionAdapter • SelectorRegionAdapter – E.g. TabControl • ItemsControlRegionAdapter – E.g. ListBox
  • 22. Defining Regions • In XAML <UserControl […] xmlns:prism="http://www.codeplex.com/prism"> […] <Controls:AnimatedTabControl x:Name="PositionBuySellTab" prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/> […] </UserControl> • In Code IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>(); RegionManager.SetRegionManager(this.ActionContent, regionManager); RegionManager.SetRegionName(this.ActionContent, "ActionRegion");
  • 23. Defining Regions • In XAML <UserControl […] xmlns:prism="http://www.codeplex.com/prism"> […] <Controls:AnimatedTabControl x:Name="PositionBuySellTab" prism:RegionManager.RegionName="{x:Static inf:RegionNames.MainRegion}"/> […] </UserControl> • In Code IRegionManager regionManager = ServiceLocator.Current.GetInstance<IRegionManager>(); RegionManager.SetRegionManager(this.ActionContent, regionManager); RegionManager.SetRegionName(this.ActionContent, "ActionRegion");
  • 24. Loading Content Into Regions // View discovery using composition container this.regionManager.RegisterViewWithRegion("MainRegion", typeof(EmployeeView)); // …or delegate this.regionManager.RegisterViewWithRegion("MainRegion", () => this.container.Resolve<EmployeeView>()); // Add view in code IRegion region = regionManager.Regions["MainRegion"]; var ordersView = container.Resolve<OrdersView>(); region.Add(ordersView, "OrdersView");
  • 25. Tips For Views and Regions • Ordering of views in a region [Export] [ViewSortHint("01")] public partial class EmailNavigationItemView [Export] [ViewSortHint("02")] public partial class CalendarNavigationItemView • Sharing data between regions – Attached property RegionContext <TabControl AutomationProperties.AutomationId="DetailsTabControl" cal:RegionManager.RegionName="{x:Static local:RegionNames.TabRegion}" cal:RegionManager.RegionContext="{Binding Path=SelectedEmployee.EmployeeId}" ...> // Read value of RegionContext private void GetRegionContext() { this.Model.EmployeeId = (int)RegionContext.GetObservableContext(this).Value; }
  • 26. Sample: Defining Regions <!-- Overview --> <ContentControl Grid.Row="1" prism:RegionManager.RegionName= "{x:Static inf:RegionAndModuleStringConstants.OverviewRegionName}" /> <GridSplitter Grid.Row="1" Style="{StaticResource VerticalGridSplitter}" /> <!-- Details --> <ContentControl Grid.Row="1" Grid.RowSpan="2" Grid.Column="1" prism:RegionManager.RegionName= "{x:Static inf:RegionAndModuleStringConstants.DetailRegionName}" /> Tip: Remove magic strings using static classes
  • 27. Sample: Defining Regions <!-- Overview --> <ContentControl Grid.Row="1" prism:RegionManager.RegionName= "{x:Static inf:RegionAndModuleStringConstants.OverviewRegionName}" /> <GridSplitter Grid.Row="1" Style="{StaticResource VerticalGridSplitter}" /> <!-- Details --> <TabControl Grid.Row="1" Grid.RowSpan="2" Grid.Column="1" prism:RegionManager.RegionName= "{x:Static inf:RegionAndModuleStringConstants.DetailRegionName}"> Note different behavior if region is an items control
  • 28. Sample Event Aggregator ActivateCustomer(11) Register customer list view to appear in this region
  • 29. Sample: UI Module namespace Prism41Sample.CustomerMaintenance { [ModuleExport("CustomerMaintenanceModule", typeof(CustomerMaintenanceModule), DependsOnModuleNames = new[] { "RepositoryModule" })] public class CustomerMaintenanceModule : IModule { [Import] private IServiceLocator serviceLocator = null; [Import] private IRegionManager regionManager = null; public void Initialize() { regionManager.RegisterViewWithRegion( RegionAndModuleStringConstants.OverviewRegionName, () => this.serviceLocator.GetInstance<CustomerList>()); } } }
  • 30. Sample: Event Aggregator [Import] private IEventAggregator eventAggregator = null; private Customer SelectedCustomerValue = default(Customer); public Customer SelectedCustomer { get { return this.SelectedCustomerValue; } set { if (this.SelectedCustomerValue != value) { this.SelectedCustomerValue = value; this.RaisePropertyChanged(() => this.SelectedCustomer); this.eventAggregator.GetEvent<ActivateCustomerEvent>() .Publish(this.SelectedCustomer.CustomerNumber); } } }
  • 31. Sample: Event Aggregator using Microsoft.Practices.Prism.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Prism41Sample.CustomerMaintenance { public class ActivateCustomerEvent : CompositePresentationEvent<int> { } }
  • 33. Navigation • Basic navigation IRegion mainRegion = ...; mainRegion.RequestNavigate(new Uri("InboxView", UriKind.Relative)); // or IRegionManager regionManager = ...; regionManager.RequestNavigate("MainRegion", new Uri("InboxView", UriKind.Relative)); • Prerequisite (for MEF): Export of the view [Export("InboxView")] public partial class InboxView : UserControl • Parameters for navigation Employee employee = Employees.CurrentItem as Employee; if (employee != null) { UriQuery query = new UriQuery(); query.Add("ID", employee.Id); _regionManager.RequestNavigate(RegionNames.TabRegion, new Uri("EmployeeDetailsView" + query.ToString(), UriKind.Relative)); }
  • 34. Sample: Event Aggregator [Export] public class MainWindowViewModel : NotificationObject { private IEventAggregator eventAggregator = null; [Import] private IRegionManager regionManager = null; [ImportingConstructor] public MainWindowViewModel(IEventAggregator eventAggregator) { this.eventAggregator = eventAggregator; this.eventAggregator.GetEvent<ActivateCustomerEvent>().Subscribe(this.OnActivateCustomer); } #region Main window controller // You should implement the controller in a separate class if navigation is more complex. private void OnActivateCustomer(int customerNumber) { var q = new UriQuery(); q.Add("CustomerNumber", customerNumber.ToString()); this.regionManager.RequestNavigate( RegionAndModuleStringConstants.DetailRegionName, new Uri("CustomerDetail" + q.ToString(), UriKind.Relative)); } #endregion
  • 36. Command Objects • Implement ICommand yourself • Use Prism's DelegateCommand<T> public class DelegateCommand<T> : DelegateCommandBase { public DelegateCommand( Action<T> executeMethod, Func<T,bool> canExecuteMethod ) : base((o) => executeMethod((T)o), (o) => canExecuteMethod((T)o)) { ... } }
  • 37. Sample: Delegate Command public class MainWindowViewModel : NotificationObject { [ImportingConstructor] public MainWindowViewModel(IEventAggregator eventAggregator) { this.CloseAllTabsCommand = new DelegateCommand(this.OnCloseAllTabs); … } public ICommand CloseAllTabsCommand { get; private set; } private void OnCloseAllTabs() { var detailRegion = this.regionManager.Regions[ RegionAndModuleStringConstants.DetailRegionName]; foreach (var view in detailRegion.Views) { // if the view implements IDisposable, call Dispose on it var disposableView = view as IDisposable; if (disposableView != null) { disposableView.Dispose(); } detailRegion.Remove(view); } } … }
  • 38. Command Objects With Interaction Triggers • Use commands with controls that does not support commands out of the box • Defined in Expression Blend – Tip: Reference assemblies come with Prism • Example: <UserControl […] xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"> […] <TextBlock Margin="5" Text="Hello World!"> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding Path=MyCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBlock> […] </UserControl> • Use CallMethodAction to call methods without ICommand – No support for parameters
  • 39. Composite Commands (1/2) • Implemented in CompositeCommand – RegisterCommand – UnregisterCommand Source: Prism 4 documentation (Microsoft)
  • 40. Composite Commands (2/2) • Implement IActiveAware on View or ViewModel class • Implement IActiveAware on your commands – DelegateCommand and CompositeCommand already implement IActiveAware • When View/ViewModel becomes inactive, deactivate child commands • Specify true in monitorCommandActivity of constructor of CompositeCommand
  • 41. Interaction Services (WPF) • ViewModel communicates with View using an interaction service var result = interactionService.ShowMessageBox( "Are you sure you want to cancel this operation?", "Confirm", MessageBoxButton.OK ); if (result == MessageBoxResult.Yes) { CancelRequest(); } • Note: Silverlight not covered here
  • 42. Sample: Composite Commands namespace Prism41Sample.UI.ViewModel { [Export(typeof(IGlobalCommands))] [PartCreationPolicy(CreationPolicy.Shared)] public class GlobalCommands : IGlobalCommands { public GlobalCommands() { this.SaveAllCommand = new CompositeCommand(); this.PrintActiveItem = new CompositeCommand(true); } public CompositeCommand SaveAllCommand { get; private set; } public CompositeCommand PrintActiveItem { get; private set; }
  • 43. Sample: Composite Commands #region IGlobalCommands implementation public void RegisterSaveAllCommand(ICommand subCommand) { this.SaveAllCommand.RegisterCommand(subCommand); } public void RegisterPrintActiveItemCommand(ICommand subCommand) { this.PrintActiveItem.RegisterCommand(subCommand); } public void UnregisterSaveAllCommand(ICommand subCommand) { this.SaveAllCommand.UnregisterCommand(subCommand); } public void UnregisterPrintActiveItemCommand( ICommand subCommand) { this.PrintActiveItem.UnregisterCommand(subCommand); } #endregion } }
  • 44. Sample: Composite Commands namespace Prism41Sample.CustomerMaintenance.ViewModel { [Export] [PartCreationPolicy(CreationPolicy.NonShared)] public class CustomerDetailViewModel : NotificationObject, ITitledViewModel, INavigationAware, IActiveAware, IDisposable { private RepositoryBase repository = null; private IGlobalCommands globalCommands; private DelegateCommand saveAllCommand; private DelegateCommand printCommand; [ImportingConstructor] public CustomerDetailViewModel(RepositoryBase repository, IGlobalCommands globalCommands) { this.repository = repository; this.globalCommands = globalCommands; this.globalCommands.RegisterSaveAllCommand( this.saveAllCommand = new DelegateCommand( () => Debug.WriteLine( "Saving Customer {0}", this.SelectedCustomer.CustomerNumber))); this.globalCommands.RegisterPrintActiveItemCommand( this.printCommand = new DelegateCommand( () => Debug.WriteLine( "Printing Customer {0}", this.SelectedCustomer.CustomerNumber))); }
  • 45. Sample: Composite Commands ~CustomerDetailViewModel() { this.Dispose(false); } private Customer SelectedCustomerValue = default(Customer); public Customer SelectedCustomer { get { return this.SelectedCustomerValue; } set { if (this.SelectedCustomerValue != value) { this.SelectedCustomerValue = value; this.RaisePropertyChanged(() => this.SelectedCustomer); } } }
  • 46. Sample: Composite Commands public bool IsNavigationTarget(NavigationContext navigationContext) { return this.GetCustomerNumberFromParameters(navigationContext) == this.SelectedCustomer.CustomerNumber; } public void OnNavigatedFrom(NavigationContext navigationContext) { } public void OnNavigatedTo(NavigationContext navigationContext) { this.SelectedCustomer = this.repository .Customers .Where(c => c.CustomerNumber == this.GetCustomerNumberFromParameters(navigationContext)) .FirstOrDefault(); } private int GetCustomerNumberFromParameters(NavigationContext navigationContext) { return Int32.Parse(navigationContext.Parameters["CustomerNumber"]); }
  • 47. Sample: Composite Commands private bool IsActiveValue = default(bool); public bool IsActive { get { return this.IsActiveValue; } set { if (this.IsActiveValue != value) { this.IsActiveValue = value; this.printCommand.IsActive = this.IsActive; this.RaisePropertyChanged(() => this.IsActive); if (this.IsActiveChanged != null) { this.IsActiveChanged(this, new EventArgs()); } } } } public event EventHandler IsActiveChanged;
  • 48. Sample: Composite Commands public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposing) { this.globalCommands.UnregisterSaveAllCommand(this.saveAllCommand); this.globalCommands.UnregisterPrintActiveItemCommand(this.printCommand); } } } }
  • 49. Q&A Thank you for your attention! Rainer Stropek software architects rainer@timecockpit.com http://www.timecockpit.com
  • 50. is the leading time tracking solution for knowledge workers. Graphical time tracking calendar, automatic tracking of your work using signal trackers, high level of extensibility and customizability, full support to work offline, and SaaS deployment model make it the optimal choice especially in the IT consulting business. Try for free and without any risk. You can get your trial account at http://www.timecockpit.com. After the trial period you can use for only 0,20€ per user and month without a minimal subscription time and without a minimal number of users.
  • 51. ist die führende Projektzeiterfassung für Knowledge Worker. Grafischer Zeitbuchungskalender, automatische Tätigkeitsaufzeichnung über Signal Tracker, umfassende Erweiterbarkeit und Anpassbarkeit, volle Offlinefähigkeit und einfachste Verwendung durch SaaS machen es zur Optimalen Lösung auch speziell im IT-Umfeld. Probieren Sie kostenlos und ohne Risko einfach aus. Einen Testzugang erhalten Sie unter http://www.timecockpit.com. Danach nutzen Sie um nur 0,20€ pro Benutzer und Tag ohne Mindestdauer und ohne Mindestbenutzeranzahl.