当DataContext已经设置为视图模型时,在XAML中引用视图成员

本文关键字:视图 XAML 成员 引用 模型 DataContext 设置 | 更新日期: 2023-09-27 18:17:29

我想知道为什么我不能从后面的代码直接引用共享的部分类成员,在xaml绑定中(没有在DataContext上设置部分类的实例)。

从我的阅读中,我理解XAML中的x:Class属性相当于CLR中的部分类声明。这就是为什么可以通过节点的'Name'属性在后面的代码中引用XAML节点。为什么不能从XAML中引用在后面代码中的部分类中实现的对象?

我意识到我可以设置一个DataContext,但我更喜欢在共享的部分类(负责视图内容和行为)中组合视图,并在DataContext上设置视图模型对象,如下所示:

mainWindow.xaml

<Window x:Class="button_binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="0,0,183,134">
        <Button x:Name="button0" Command="{Binding Button0.DelegateClick}" Content="{Binding Button0.Content}" HorizontalAlignment="Left" Margin="112,82,0,0" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button1" Command="{Binding Button1.DelegateClick}" Content="{Binding Button1.Content}" HorizontalAlignment="Left" Margin="112,134,0,0" VerticalAlignment="Top" Width="75"/>
        <ToggleButton Name="button2" IsChecked="{Binding Button2.On, Mode=OneWayToSource}" Content="{Binding Button2.Content}" HorizontalAlignment="Left" Margin="213,134,0,0" VerticalAlignment="Top"/>
        <Button Content="MODEL" Command="{Binding VM.TargetButton.Push}" HorizontalAlignment="Left" Margin="273,86,-14,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

mainWindow.xaml.cs

namespace button_binding
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableButton Button0 { get; set; }
        public ObservableButton Button1 { get; set; }
        public ObservableToggleButton Button2 { get; set; }
        public ViewModel VM { get; set; }
        public MainWindow ()
        {
            // finish off the view build
            //   These objects contain pure view state and UI behaviour
            //   no reference to model or view controls!
            Button0 = new ObservableButton(new List<string> { "Paused", "Logging" }, false);
            Button1 = new ObservableButton(new List<string> { "Paused", "Logging" }, false);
            Button2 = new ObservableToggleButton(new List<string> { "Log All", "Log VBA" }, false);
            InitializeComponent();
            // build the view model and connect it to the view
            VM = new ViewModel(button2);
            DataContext = VM;    //<-- this is what I want to do
//          DataContext = this;  //<-- this is what I have to do
        }
    }
}

当DataContext已经设置为视图模型时,在XAML中引用视图成员

如注释所示…

命名主窗口,并在绑定

中使用ElementName
<Window x:Class="button_binding.MainWindow"
        x:Name="View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="0,0,183,134">
        <Button x:Name="button0" Command="{Binding ElementName=View, Path=Button0.DelegateClick}" Content="{Binding ElementName=View, Path=Button0.Content}" HorizontalAlignment="Left" Margin="112,82,0,0" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button1" Command="{Binding ElementName=View, Path=Button1.DelegateClick}" Content="{Binding ElementName=View, Path=Button1.Content}" HorizontalAlignment="Left" Margin="112,134,0,0" VerticalAlignment="Top" Width="75"/>
        <ToggleButton Name="button2" IsChecked="{Binding ElementName=View, Path=Button2.On, Mode=OneWayToSource}" Content="{Binding ElementName=View, Path=Button2.Content}" HorizontalAlignment="Left" Margin="213,134,0,0" VerticalAlignment="Top"/>
        <Button Content="MODEL" Command="{Binding TargetButton.Push}" HorizontalAlignment="Left" Margin="273,86,-14,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

使用RelativeSource FindAncestor

<Window x:Class="button_binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid Margin="0,0,183,134">
        <Button x:Name="button0" Command="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button0.DelegateClick}" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button0.Content}" HorizontalAlignment="Left" Margin="112,82,0,0" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button1" Command="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button1.DelegateClick}" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button1.Content}" HorizontalAlignment="Left" Margin="112,134,0,0" VerticalAlignment="Top" Width="75"/>
        <ToggleButton Name="button2" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button2.On, Mode=OneWayToSource}" Content="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}}, Path=Button2.Content}" HorizontalAlignment="Left" Margin="213,134,0,0" VerticalAlignment="Top"/>
        <Button Content="MODEL" Command="{Binding TargetButton.Push}" HorizontalAlignment="Left" Margin="273,86,-14,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

<Window x:Class="button_binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <RelativeSource x:Key="View" Mode="FindAncestor" AncestorType="{x:Type Window}"></RelativeSource>
    </Window.Resources>
    <Grid Margin="0,0,183,134">
        <Button x:Name="button0" 
                Command="{Binding Button0.DelegateClick, RelativeSource={StaticResource View}}" 
                Content="{Binding Button0.Content, RelativeSource={StaticResource View}}" 
                HorizontalAlignment="Left" Margin="112,82,0,0" VerticalAlignment="Top" Width="75"/>
        <Button x:Name="button1" Command="{Binding Button1.DelegateClick, RelativeSource={StaticResource View}}" 
                Content="{Binding Button1.Content, RelativeSource={StaticResource View}}" 
                HorizontalAlignment="Left" Margin="112,134,0,0" VerticalAlignment="Top" Width="75"/>
        <ToggleButton Name="button2" IsChecked="{Binding Button2.On, RelativeSource={StaticResource View}, Mode=OneWayToSource}" 
                Content="{Binding Button2.Content, RelativeSource={StaticResource View}}" 
                HorizontalAlignment="Left" Margin="213,134,0,0" VerticalAlignment="Top"/>
        <Button Content="MODEL" Command="{Binding TargetButton.Push}" HorizontalAlignment="Left" 
                Margin="273,86,-14,0" VerticalAlignment="Top" Width="75"/>
    </Grid>
</Window>

然后,在后面的代码中,可以删除VM对象并只执行…

        // build the view model and connect it to the view
        DataContext = new ViewModel(button2);