Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save miklund/09d66d1dca1161081d3b to your computer and use it in GitHub Desktop.
Save miklund/09d66d1dca1161081d3b to your computer and use it in GitHub Desktop.
2012-11-28 Composite applications in WPF: Part 1 - Setting it up
# Title: Composite applications in WPF: Part 1 - Setting it up
# Author: Mikael Lundin
# Link: http://blog.mikaelundin.name/2012/11/28/composite-applications-in-wpf-part-1-setting-it-up.html
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
namespace CompositeWPF
{
using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Modularity;
using System.ComponentModel.Composition.Hosting;
using System.Threading.Tasks;
using System.Windows;
public class Bootstrapper : MefBootstrapper
{
protected override System.Windows.DependencyObject CreateShell()
{
return new MainWindow();
}
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (MainWindow)this.Shell;
Application.Current.MainWindow.Show();
}
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
// Add this assembly
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));
// Modules are copied to a directory as part of a post-build step.
// These modules are not referenced in the project and are discovered by
// inspecting a directory.
// Projects have a post-build step to copy themselves into that directory.
DirectoryCatalog catalog = new DirectoryCatalog(".");
this.AggregateCatalog.Catalogs.Add(catalog);
}
}
}
<UserControl x:Class="CompositeWPF.ShoeSize.View.ContentControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<!-- Wrap elements that stacks vertically -->
<Style x:Key="wrapper" TargetType="StackPanel">
<Setter Property="Margin" Value="10" />
<Setter Property="Orientation" Value="Vertical" />
</Style>
<!-- Represents a row in the form -->
<Style x:Key="row" TargetType="DockPanel">
<Setter Property="Margin" Value="0 0 0 5" />
</Style>
<!-- Input element in the grid -->
<Style x:Key="label" TargetType="TextBlock">
<Setter Property="DockPanel.Dock" Value="Top" />
</Style>
<!-- Input element in the grid -->
<Style x:Key="input" TargetType="TextBox">
<Setter Property="DockPanel.Dock" Value="Left" />
<Setter Property="Width" Value="auto" />
</Style>
<!-- Submitbutton -->
<Style x:Key="submit" TargetType="Button">
<Setter Property="Margin" Value="0 0 0 5" />
</Style>
<!-- What is your name? -->
<clr:String x:Key="name_content">What is your name?</clr:String>
<!-- What is your shoe size? -->
<clr:String x:Key="shoesize_content">What is your shoe size?</clr:String>
<!-- Submit button text -->
<clr:String x:Key="submit_content">Submit</clr:String>
</UserControl.Resources>
<StackPanel Style="{StaticResource wrapper}">
<DockPanel Style="{StaticResource row}">
<TextBlock Style="{StaticResource label}" Text="{StaticResource name_content}" />
<TextBox Style="{StaticResource input}" Text="{Binding Path=Name}" />
</DockPanel>
<DockPanel Style="{StaticResource row}">
<TextBlock Style="{StaticResource label}" Text="{StaticResource shoesize_content}" />
<TextBox Style="{StaticResource input}" Text="{Binding Path=ShoeSize}" />
</DockPanel>
<StackPanel Style="{StaticResource wrapper}">
<Button Style="{StaticResource submit}" Command="{Binding SubmitCommand}" Content="{StaticResource submit_content}"></Button>
<TextBlock Text="{Binding Message}"></TextBlock>
</StackPanel>
</StackPanel>
</UserControl>
[Export]
public partial class ContentControl : UserControl
{
public ContentControl()
{
InitializeComponent();
this.DataContext = new ContentViewModel();
}
}
[Export("ShoeSizeContent")]
public partial class ContentControl : UserControl
{
public ContentControl()
{
InitializeComponent();
this.DataContext = new ContentViewModel();
}
}
using Microsoft.Practices.Prism.Commands;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
public class ContentViewModel : INotifyPropertyChanged
{
private string name;
private int shoeSize;
private string message;
public event PropertyChangedEventHandler PropertyChanged;
public ContentViewModel()
{
SubmitCommand = new DelegateCommand<object>(this.OnSubmit, this.CanSubmit);
}
public string Name
{
get { return this.name; }
set
{
if (this.name != value)
{
this.name = value;
NotifyPropertyChanged();
}
}
}
public int ShoeSize
{
get { return this.shoeSize; }
set
{
if (this.shoeSize != value)
{
this.shoeSize = value;
NotifyPropertyChanged();
}
}
}
public string Message
{
get { return this.message; }
set
{
if (this.message != value)
{
this.message = value;
NotifyPropertyChanged();
}
}
}
public ICommand SubmitCommand { get; private set; }
private bool CanSubmit(object arg)
{
return true;
}
private void OnSubmit(object arg)
{
this.Message = string.Format("Hello {0}, your shoe size is {1}!", Name, ShoeSize);
}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
[Export]
public partial class NavigationButton : UserControl
{
[ImportingConstructor]
public NavigationButton(NavigationViewModel viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}
<UserControl x:Class="CompositeWPF.ShoeSize.View.NavigationButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<UserControl.Resources>
<Style x:Key="icon" TargetType="Button">
<Setter Property="Width" Value="24" />
<Setter Property="Height" Value="24" />
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</Style>
<BitmapImage x:Key="simple-icon" UriSource="../Resources/icon.png" />
</UserControl.Resources>
<Grid>
<Button Style="{StaticResource icon}" Command="{Binding NavigateCommand}">
<Image Source="{StaticResource simple-icon}" />
</Button>
</Grid>
</UserControl>
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Events;
using System.ComponentModel.Composition;
using System.Windows.Input;
[Export]
public class NavigationViewModel
{
private IEventAggregator eventAggregator;
[ImportingConstructor]
public NavigationViewModel(IEventAggregator eventAggregator)
{
this.eventAggregator = eventAggregator;
this.NavigateCommand = new DelegateCommand<object>(this.OnNavigate, this.CanNavigate);
}
public ICommand NavigateCommand { get; private set; }
private bool CanNavigate(object arg)
{
return true;
}
private void OnNavigate(object arg)
{
this.eventAggregator.GetEvent<NavigationEvent>().Publish("ContentRegion");
}
}
public class NavigationEvent : CompositePresentationEvent<string>
{
}
using CompositeWPF.ShoeSize.View;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using System.ComponentModel.Composition;
[ModuleExport(typeof(ShoeSize))]
public class ShoeSize : IModule
{
private IRegionManager regionManager;
[ImportingConstructor]
public ShoeSize(IRegionManager regionManager)
{
this.regionManager = regionManager;
}
public void Initialize()
{
// add views to regions
regionManager.RegisterViewWithRegion("ButtonRegion", typeof(NavigationButton));
regionManager.RegisterViewWithRegion("ContentRegion", typeof(ContentControl));
}
}
using CompositeWPF.ShoeSize.View;
using CompositeWPF.ShoeSize.ViewModel;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using System.ComponentModel.Composition;
[ModuleExport(typeof(ShoeSize))]
public class ShoeSize : IModule
{
private IRegionManager regionManager;
private IEventAggregator eventAggregator;
[ImportingConstructor]
public ShoeSize(IRegionManager regionManager, IEventAggregator eventAggregator)
{
this.regionManager = regionManager;
this.eventAggregator = eventAggregator;
}
public void Initialize()
{
regionManager.RegisterViewWithRegion("ButtonRegion", typeof(NavigationButton));
this.eventAggregator.GetEvent<NavigationEvent>().Subscribe(NavigateTo);
}
private void NavigateTo(string regionName)
{
regionManager.RequestNavigate(regionName, "ShoeSizeContent");
}
}
<Window x:Class="CompositeWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://www.codeplex.com/CompositeWPF"
Width="525" Height="350"
Title="Modular UI with Composite WPF Application">
<Window.Resources>
<!-- Button Bar Panel -->
<Style x:Key="button_panel" TargetType="StackPanel">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="Background" Value="Beige" />
<Setter Property="DockPanel.Dock" Value="Top" />
</Style>
<!-- Content Region Panel -->
<Style x:Key="content_panel" TargetType="DockPanel">
<Setter Property="DockPanel.Dock" Value="Bottom" />
</Style>
<!-- Region -->
<Style x:Key="region" TargetType="ItemsControl">
<Setter Property="Padding" Value="5" />
</Style>
</Window.Resources>
<DockPanel>
<StackPanel Style="{StaticResource button_panel}">
<ItemsControl prism:RegionManager.RegionName="ButtonRegion" Style="{StaticResource region}" />
</StackPanel>
<DockPanel Style="{StaticResource content_panel}">
<ItemsControl prism:RegionManager.RegionName="ContentRegion" Style="{StaticResource region}" />
</DockPanel>
</DockPanel>
</Window>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment