| Украина |
Построение кроссплатформенного Silverlight/WPF приложения
Вместе с проектами были автоматически созданы главные окна, MainWindow.xaml и MainPage.xml, для WPF и Silverlight соответственно. Так как эти сущности различны в двух версиях (в случае WPF это окно, в Silverlight – UserControl), их невозможно повторно использовать. Однако в них можно поместить приведенный в "Реализация паттерна MVVM с использованием IoC-контейнера, как метод избавления от зависимости между компонентами системы" элемент управления ViewModelPresenter, который будет делегировать создание внутренней разметки представлению, соответствующему находящейся в DataContext модели представления.
MainWindow.xaml:
1: <Window x:Class="CrossPlatformApplication.MainWindow"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:view="clr-namespace:CrossPlatformApplication"
5: Title="{Binding Title}" SizeToContent="WidthAndHeight">
6:
7: <view:ViewModelPresenter ViewModel="{Binding}" />
8: </Window>MainPage.xaml:
1: <UserControl x:Class="SilverlightApplication.MainPage"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:view="clr-namespace:CrossPlatformApplication">
5:
6: <view:ViewModelPresenter ViewModel="{Binding}" />
7: </UserControl>Согласно принципам MVVM главному представлению приложения должна соответствовать модель представления. Для начала достаточно пустого класса, общего для WPF и Silverlight:
1: [Export]
2: [PartCreationPolicy(CreationPolicy.NonShared)]
3: [ExportMetadata(AopExtensions.AspectMetadata,
4: Aspects.NotifyPropertyChanged)]
5: public class MainViewModel : IEntitledViewModel
6: {
7: public string Title
8: {
9: get { return "Test Application"; }
10: }
11: }Затем для корректного запуска приложения необходимо добавить логику инициализации IoC контейнера MEF и MVVM окружения, а также модифицировать логику отображения главных окон. Как в WPF, так и в Silverlight приложении модифицируется код App.xaml и App.xaml.cs.
1: <Application x:Class="WpfApplication.App" 2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 4: <Application.Resources> 5: 6: </Application.Resources> 7: </Application>
1: public partial class App
2: {
3: #region Injected properties
4:
5: [Import]
6: public ChildViewManager ChildViewManager
7: { private get; set; }
8:
9: #endregion
10:
11: protected override void OnStartup(StartupEventArgs e)
12: {
13: base.OnStartup(e);
14:
15: // Create interception configuration
16: var cfg = new InterceptionConfiguration()
17: .AddAopInterception();
18:
19: var container = new CompositionContainer(
20: new InterceptingCatalog(new AggregateCatalog(
21: new DirectoryCatalog(".", "*.exe"),
22: new DirectoryCatalog(".", "*.dll")), cfg));
23:
24: var locator = new MefServiceLocator(container);
25: ServiceLocator.SetLocatorProvider(() => locator);
26: container.ComposeExportedValue<IServiceLocator>(locator);
27: container.ComposeParts(this);
28:
29: new MainWindow { DataContext =
30: locator.GetInstance<MainViewModel>() }.Show();
31: }
32: }1: <Application x:Class="SilverlightApplication.App" 2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 4: <Application.Resources> 5: 6: </Application.Resources> 7: </Application>
1: public partial class App
2: {
3: public App()
4: {
5: Startup += Application_Startup;
6: Exit += Application_Exit;
7: UnhandledException += Application_UnhandledException;
8:
9: InitializeComponent();
10: }
11:
12: #region Injected properties
13:
14: [Import]
15: public ChildViewManager ChildViewManager
16: { private get; set; }
17:
18: #endregion
19:
20: private void Application_Startup
21: (object sender, StartupEventArgs e)
22: {
23: // Create interception configuration
24: var cfg = new InterceptionConfiguration()
25: .AddAopInterception();
26:
27: var container = new CompositionContainer(
28: new InterceptingCatalog(
29: new DeploymentCatalog(), cfg));
30: var locator = new MefServiceLocator(container);
31: ServiceLocator.SetLocatorProvider(() => locator);
32: container.ComposeExportedValue<IServiceLocator>(locator);
33: container.ComposeParts(this);
34:
35: RootVisual = new MainPage
36: { DataContext = locator.GetInstance<MainViewModel>() };
37: }
38:
39: private void Application_Exit(object sender, EventArgs e)
40: {
41:
42: }
43:
44: private void Application_UnhandledException
46: (object sender, ApplicationUnhandledExceptionEventArgs e)
47: {
48: if (!System.Diagnostics.Debugger.IsAttached)
49: {
50: e.Handled = true;
51: Deployment.Current.Dispatcher.BeginInvoke(
52: delegate { ReportErrorToDOM(e); });
53: }
54: }
55:
56: private void ReportErrorToDOM
57: (ApplicationUnhandledExceptionEventArgs e)
44: {
45: try
46: {
47: string errorMsg = e.ExceptionObject.Message
48: + e.ExceptionObject.StackTrace;
49: errorMsg = errorMsg.Replace('"',
50: '\'').Replace("\r\n", @"\n");
51:
52: System.Windows.Browser.HtmlPage.Window.Eval(
53: "throw new Error(\"Unhandled Error in Silverlight Application "
54: + errorMsg + "\");");
55: }
56: catch (Exception)
57: {
58: }
59: }
60: }Как видно из кода, главные окна приложения будут отображать представление MainView, соответствующее модели представления MainViewModel. Пусть это представление будет содержать простой текст "Hello world":
1: <UserControl x:Class="CrossPlatformApplication.MainView" 2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5: xmlns:mc 6: ="http://schemas.openxmlformats.org/markup-compatibility/2006" 7: mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> 8: 9: <Grid x:Name="LayoutRoot" Background="White" MinHeight="150" 10: MinWidth="200"> 11: <TextBlock Text="Hello world" 12: HorizontalAlignment="Center" 13: VerticalAlignment="Center" /> 14: </Grid> 15: </UserControl>
Естественно, как говорилось в "Особенности отображения диалоговых окон в WPF и Silverlight версиях приложения" , необходимо создать представление в Silverlight проекте и добавить ссылку на него в WPF проект. Теперь оба приложения готовы к запуску и отображают на своем главном окне сообщение "Hello world".
Следующим этапом следует некоторое усложнение примера – размещенная на главном представлении кнопка будет отображать модальное дочернее окно, считывающее строку у пользователя. Введенные данные модифицируют исходный текст на главном представлении.