在WinRT中使用多个ViewModel

时间:2014-09-16 18:19:06

标签: mvvm windows-runtime

操作系统:Windows 8.1
IDE :VS 2013 Express for Windows
项目:通用
目标:Windows 8.1,Phone 8.1
IoC :MEF

我的Windows应用程序基于本指南" Hierarchical navigation, start to finish"在 Windows开发人员中心上。我使用MEF将ViewModel注入视图。

MainPage 位于 .Shared Project HubPage ItemPage SectionPage < / strong>在视角窗口电话项目

每个页面都有自己的 ViewModel ,位于程序集中,名为 UILogic 。在启动期间,所有 ViewModels 都成功注入视图。但是,查看立即窗口,我得到此绑定错误

Windows 8.1

Error: BindingExpression path error: 'HubSectionHeaderCommand' property not found on 'NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. BindingExpression: Path='HubSectionHeaderCommand' DataItem='NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Microsoft.Xaml.Interactions.Core.InvokeCommandAction' (Name='null'); target property is 'Command' (type 'ICommand')
Error: BindingExpression path error: 'DefaultDataModel' property not found on 'NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. BindingExpression: Path='DefaultDataModel' DataItem='NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Windows.UI.Xaml.Data.CollectionViewSource' (Name='null'); target property is 'Source' (type 'Object')
Error: BindingExpression path error: 'NavigationHelper' property not found on 'NathsarTS.Views.HubPage'. BindingExpression: Path='NavigationHelper.GoBackCommand' DataItem='NathsarTS.Views.HubPage'; target element is 'Windows.UI.Xaml.Controls.Button' (Name='backButton'); target property is 'Command' (type 'ICommand')
Error: BindingExpression path error: 'Section3Items' property not found on 'NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. BindingExpression: Path='Section3Items' DataItem='NathsarTS.UILogic.ViewModels.MainPageViewModel, NathsarTS.UILogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'Windows.UI.Xaml.Controls.HubSection' (Name='null'); target property is 'DataContext' (type 'Object')

MainPage 如下所示:

<Grid x:Name="LayoutRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Frame x:Name="rootFrame"/>

HubPage 看起来像这样在启动时也会导航:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
...
..
<Hub >
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="SectionHeaderClick">
            <core:InvokeCommandAction Command="{Binding HubSectionHeaderCommand}"/>
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
    <Hub.Header>
        <!-- Back button and page title -->
        <Grid>
            ...
            ..
            <Button  x:Name="backButton" Style="{StaticResource NavigationBackButtonNormalStyle}"
                Margin="0,0,39,0" 
                VerticalAlignment="Top"
                Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                AutomationProperties.Name="Back"
                AutomationProperties.AutomationId="BackButton"
                AutomationProperties.ItemType="Navigation Button"/>
            ...
            ..
        </Grid>
    </Hub.Header>
    ...
    ..
    <HubSection IsHeaderInteractive="True" 
                DataContext="{Binding Section3Items}" 
                d:DataContext="{Binding Groups[3], Source={d:DesignData Source=../NathsarTS.Shared/DataModel/SampleData.json, Type=data:SampleDataSource}}"
                x:Uid="Section3Header" Header="Section 3" Padding="40,40,40,32">
        <DataTemplate>
            <GridView
                x:Name="itemGridView"
                ItemsSource="{Binding Items}"
                Margin="-9,-14,0,0"
                AutomationProperties.AutomationId="ItemGridView"
                AutomationProperties.Name="Items In Group"
                ItemTemplate="{StaticResource Standard310x260ItemTemplate}"
                SelectionMode="None"
                IsSwipeEnabled="false"
                IsItemClickEnabled="True">
                <interactivity:Interaction.Behaviors>
                    <core:EventTriggerBehavior EventName="ItemClick">
                        <core:InvokeCommandAction Command="{Binding HubSectionGridItemCommand}"/>
                    </core:EventTriggerBehavior>
                </interactivity:Interaction.Behaviors>
            </GridView>
        </DataTemplate>
    </HubSection>
    ...
    ..
</Hub>

我的绑定报告未在 MainPageViewModel 上报告,但它们在 HubPageViewModel 中定义。

MEF 以这种方式注入 ViewModels

[Export(typeof(HubPage))]
public sealed partial class HubPage : Page
{
public HubPage()
{
    this.InitializeComponent();
    Debug.WriteLine("HubPage InitializeComponent");
}

[Import]
public NathsarTS.UILogic.Interfaces.IHubPageViewModel ViewModel
{
    set
    {
        this.DataContext = value;
    }
    get
    {
        return DataContext as NathsarTS.UILogic.Interfaces.IHubPageViewModel;
    }
}

/// <summary>
/// Called when a part's imports have been satisfied and it is safe to use.
/// </summary>
[OnImportsSatisfied]
public void OnImportsSatisfied()
{
    // IPartImportsSatisfiedNotification is useful when you want to coordinate doing some work
    // with imported parts independent of when the UI is visible.
    Debug.WriteLine("HubPage OnImportsSatisfied instantiation");

    //NathsarTS.UILogic.Interfaces.IObservableService ObservableService = ServiceLocator.Current.GetInstance<NathsarTS.UILogic.Interfaces.IObservableService>();
    this.ViewModel.NavigationHelper = new NathsarTS.Common.Logic.NavigationHelper(this);
    this.ViewModel.NavigationHelper.LoadState += this.ViewModel.NavigationHelperLoadState;
}
}
WinRT 中是否允许 ViewModels PageView

IN ADDTION :我在启动时也注意到这一点,HubPage正在初始化两次。为什么:

MainPage InitializeComponent
PropertiesService instantiation
MainPageViewModel instantiation
MainPage OnImportsSatisfied instantiation
HubPage InitializeComponent
HubPageViewModel instantiation
HubPage OnImportsSatisfied instantiation
HubPage InitializeComponent
HubPage OnNavigatedTo instantiation

这是我在创业期间所做的事情:

protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
    this._configuration.WithAssembly(typeof(App).GetTypeInfo().Assembly)
        .WithAssembly(typeof(NathsarTS.UILogic.UILogicBusinessLogic).GetTypeInfo().Assembly)
        .WithAssembly(typeof(NathsarTS.Common.CommonBusinessLogic).GetTypeInfo().Assembly)
        .WithAssembly(typeof(NathsarTS.ODSDocuments.ODSDocumentsBusinessLogic).GetTypeInfo().Assembly);
    this._compositionHost = this._configuration.CreateContainer();

    await ShowWindow(args);
}

private async Task ShowWindow(LaunchActivatedEventArgs e)
{
    MainPage mainPage = Window.Current.Content as MainPage;
    Frame rootFrame = null;

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (mainPage == null)
    {
        mainPage = _compositionHost.GetExport<MainPage>();
    }

    // Retrieve the root Frame to act as the navigation context and navigate to the first page
    // Don't change the name of "rootFrame" in MainPage.xaml unless you change it here to match.
    rootFrame = (Frame)mainPage.FindName("rootFrame");
    if (rootFrame != null)
    {
        // Associate the frame with a SuspensionManager key.
        SuspensionManager.RegisterFrame(rootFrame, "AppFrame");

        // TODO: change this value to a cache size that is appropriate for your application
        rootFrame.CacheSize = 1;

        if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
        {
            // Restore the saved session state only when appropriate
            try
            {
                await SuspensionManager.RestoreAsync();
            }
            catch (SuspensionManagerException)
            {
                //Something went wrong restoring state.
                //Assume there is no state and continue
            }
        }

        // Place the main page in the current Window.
        Window.Current.Content = mainPage;

        if (rootFrame.Content == null)
        {
            // When the navigation stack isn't restored navigate to the first page,
            // configuring the new page by passing required information as a navigation
            // parameter
            HubPage hubPage = _compositionHost.GetExport<HubPage>();
            if (!rootFrame.Navigate(hubPage.GetType(), e.Arguments))
            {
                throw new Exception("Failed to create initial page");
            }
        }

    }

    // Ensure the current window is active
    Window.Current.Activate();
}

谢谢你的帮助!..

1 个答案:

答案 0 :(得分:0)

能够修复我的重复内容并正确地将 ViewModel 连接到 PageView 。问题是。 Navigation 1)在 MEF 进行初始化后继续重新初始化 Page 构造函数,2)由于某种原因< strong> HubPage DataContext 会丢失。

所以,这就是我解决它的方法:

protected override async Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args)
{
    Debug.WriteLine("OnLaunchApplicationAsync...");

    MainPage mainPage = _compositionHost.GetExport<MainPage>();
    Window.Current.Content = mainPage;
    Frame rootFrame = (Frame)mainPage.FindName("rootFrame");

    if (rootFrame != null)
    {
        if (rootFrame.Content == null)
        {
            // When the navigation stack isn't restored navigate to the first page,
            // configuring the new page by passing required information as a navigation
            // parameter
            HubPage hubPage = _compositionHost.GetExport<HubPage>();
            rootFrame.Content = hubPage;
        }
    }

    Window.Current.Activate();
    await Task.FromResult<object>(null);
}

而不是在初始启动时使用。导航,我只是将页面 类型分配给。内容