【问题标题】:WPF Assigning the Same DataContex to Multiple Pages MVVMWPF将相同的DataContex分配给多个页面MVVM
【发布时间】:2019-01-25 12:36:04
【问题描述】:

我有一个带有多个框架的窗口。每个框架包含一个或多个页面。所有页面使用相同的 ViewModel。我控制每个 Frame 的 Visibility 来操作 UI。

我最近意识到,当我的程序启动时,每个页面都会触发 ViewModel 的相同构造函数(因此相同的构造函数会触发多次)(构造函数中的简单 MessageBox.Show 在启动时会触发多次) .为什么会发生这种情况对我来说有点道理,但不是我想要的。

另外,我开始相信我在 C# 中处理不同框架时遇到问题的原因是因为我可能创建了 ViewModel 的新“对象”?我不确定这是不是正在发生的事情,但我很确定这不是我想要的。

有没有办法为页面设置 DataContext(在 Xaml 中),以便构造函数只触发一次,但仍将每个页面的 DataContext 设置为 ViewModel?还是我应该探索一种不同的方法?我还在学习中……

每个页面都有以下 Xaml:

<Page.DataContext>
    <ViewModel:ActiveJobViewModel/>
</Page.DataContext>

我的框架看起来像这样。我意识到一个框架可以容纳多个页面,但操纵可见性给了我更好的性能,我不希望每次页面源更改时都运行构造函数。

<Frame Source="ActiveJobPage.xaml" Grid.Row="2" Grid.Column="3" 
       Visibility="{Binding ElementName=ActiveJobPageToggleButton, Path=IsChecked, Converter={StaticResource booleanToVisibility}, UpdateSourceTrigger=PropertyChanged}" 
       Style="{StaticResource FramePage}">
</Frame>

<Frame  Source="CustomerPage.xaml" Grid.Row="2" Grid.Column="3"
        Visibility="{Binding objHomePage_PageVisibility.CustomersPageToggleButtonIsChecked, Converter={StaticResource booleanToVisibility}, UpdateSourceTrigger=PropertyChanged}"
        Style="{StaticResource FramePage}">
</Frame>

【问题讨论】:

    标签: wpf mvvm datacontext


    【解决方案1】:

    以下创建ActiveJobViewModel 类的新实例:

    <ViewModel:ActiveJobViewModel/>
    

    如果您的所有页面和框架共享相同的视图模型,您只需执行一次 - 在定义框架的窗口中。如果将视图模型定义为窗口中的资源:

    <Window ...>
        <Window.Resources>
            <ViewModel:ActiveJobViewModel x:Key="viewModel"/>
        </Window.Resources>
        <!-- frames ... -->
    </Window>
    

    ...然后您可以处理FramesLoadCompleted 事件并以编程方式设置其内容的DataContext

    private void Frame_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        Frame frame = (Frame)sender;
        FrameworkElement content = frame.Content as FrameworkElement;
        if (content != null)
            content.DataContext = Resources["viewModel"];
    }
    

    XAML:

    <Frame Source="ActiveJobPage.xaml" Grid.Row="2" Grid.Column="3"
            LoadCompleted="Frame_LoadCompleted"
            Visibility="{Binding ElementName=ActiveJobPageToggleButton, Path=IsChecked, Converter={StaticResource booleanToVisibility}, UpdateSourceTrigger=PropertyChanged}" 
            Style="{StaticResource FramePage}">
    </Frame>
    

    不要忘记从页面中删除 &lt;Page.DataContext&gt; 元素。

    【讨论】:

    • 这也是一个很好的方法。最终,我在 App.xaml 中定义了 ViewModel,然后在 xaml 中应用了页面的 dataContext。 DataContext="{StaticResource ActiveJobViewModel}"。到目前为止,这似乎按我希望的方式工作。感谢您的回复。我一直在向他们学习!
    【解决方案2】:

    从页面 XAML 中删除以下内容。

    <Page.DataContext>
        <ViewModel:ActiveJobViewModel/>
    </Page.DataContext>
    

    并在代码中手动将两个页面的DataContext设置为同一个实例。

    例如在您的 Page 代码隐藏类中。

    public void SetDataContext(ActiveJobViewModel commonContext)
    {
       this.DataContext = commonContext;
    }
    

    然后创建一个ActiveJobViewModel实例的通用实例,并为多个页面设置相同的datacontext。

    【讨论】:

    • 谢谢。您能解释一下“在代码中手动将两个页面的 DataContext 设置为同一个实例”是什么意思吗?
    • 查看更新后的答案。那有意义吗?您必须创建一个通用的 DataContext 实例并专门为多个页面设置。
    • 我几乎拥有它...我删除了 Xaml DataContext。如果这是您的意思,我将 SetDataContext 方法添加到我的每个页面中。但是,我不确定应该在哪里/如何创建 ActiveJobViewModel 的公共实例,或者如何为多个页面设置相同的 DataContext?抱歉,我有点费力地解决这个问题......
    • 在研究时,我发现了这个基于 Xaml 的答案。 stackoverflow.com/questions/4590446/… C# 或 Xaml 对我来说并不重要。我只是想理解......我相信它正在完成同样的事情。 CharithJ 你同意吗?
    • @mjordan:很抱歉我错过了你的评论。是的,这会做同样的事情。如果 DataContext 可以在运行时更改,我认为您需要 DynamicResource 。 stackoverflow.com/a/15714079/591656
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 2014-07-06
    • 1970-01-01
    • 2013-06-03
    • 1970-01-01
    • 2012-03-15
    相关资源
    最近更新 更多