通过资源设置数据上下文

Setting a datacontext via resources

显然使用“Resources”设置控件的 DataContext 与我想的不一样。我试图贴近 MVVM。下面是设置DataContext的实验。

MainWindow 有一个带有两个选项卡的 TabControl,每个选项卡都显示我宠物的名字,最初是“Sam”。单击选项卡 1 上的“ChangeName”按钮可按预期更改宠物的名称(更改为“Daisy”)。它在选项卡 2 上没有变化。

Tab 2 的内容是一个Page,有自己的DataContext,SecondTabViewModel。所以我需要调整 TextBlock 中的 DataContext 以获取 MyPet 的名称。这编译正常,并且 Intellisense 提出了正确的事情,因此以某种方式在控件内进行了设置。但是宠物的名字没有变。

“StaticResource”是否生成实例化 MainWindow 或其他东西的新副本?有人可以帮我吗?我很想知道为什么这不起作用, 会起作用。根据 https://docs.microsoft.com/en-us/dotnet/desktop/wpf/data/?view=netdesktop-5.0 上的文档,这种设置本地 DataContext 的策略应该有效,但我一定是误读了。

简而言之,我省略了一些代码(宠物 class。但是那里似乎一切正常,因为我可以更改第一个选项卡上的名称 The Pet class 实现 INotifyPropertyChanged,我正在使用正确的处理程序等)

MainWindow.xmal

<Window x:Class="WpfApp9.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp9"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <TabControl>
            <TabItem Header="First Tab" Height="50">
                <StackPanel>
                    <TextBlock Text="{Binding MyPet.Name}"/>
                    <Button Content="Change Name" 
                            Command="{Binding ChangePetNameCommand}"/>
                </StackPanel>
            </TabItem>
            <TabItem Header="Second Tab" Height="50">
                <Frame Source="SecondTab.xaml"/>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

MainWindowViewModel

public class MainWindowViewModel
{
    public Pet MyPet { get; set; }
    public ICommand ChangePetNameCommand { get; set; }
    public MainWindowViewModel()
    {
        MyPet = new Pet();

        ChangePetNameCommand = 
            new RelayCommand(ChangePetName, (Object o) => true);
    }

    public void ChangePetName(object o)
    {
        MyPet.Name = "Daisy";
    }
}   

SecondTab.xmal

<Page x:Class="WpfApp9.SecondTab"
      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:local="clr-namespace:WpfApp9"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800"
      Title="SecondTab">
    <Page.DataContext>
        <local:SecondTabViewModel/>
    </Page.DataContext>
    <Page.Resources>
        <local:MainWindowViewModel x:Key="M"/>
    </Page.Resources>

    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Source={StaticResource M},     
                                      Path = MyPet.Name}"/>                            
          </StackPanel> 
    </Grid>
</Page>

SecondTabviewModel

namespace WpfApp9
{
    public class SecondTabViewModel
    {
        public SecondTabViewModel()
        {

        }
    }
}

线条

<Page.Resources>
    <local:MainWindowViewModel x:Key="M"/>
</Page.Resources>

在 SecondTab.xaml 中正在创建第二个 MainWindowViewModel 实例。

也就是说SecondTab并没有对原来的MainWindowViewModel进行操作

您将不得不以某种方式将对原始 MainWindowViewModel 实例的引用传递给 SecondTabViewModel。


SecondTab 可能不是使用 Frame 和 Page,而是简单地从其父元素继承 DataContext 的 UserControl,并且您可以传递一个视图模型对象,例如

<TabItem Header="Second Tab" Height="50">
    <local:SecondTab DataContext="{Binding SecondTabVM}"/>
</TabItem>

其中 SecondTabVM 是包含 SecondTabViewModel 实例的 MainWindowViewModel 的 属性。