绑定到 DataTemplate 中的视图模型属性

Posted

技术标签:

【中文标题】绑定到 DataTemplate 中的视图模型属性【英文标题】:Binding to a viewmodel property in a DataTemplate 【发布时间】:2013-03-22 19:55:56 【问题描述】:

我对 XAML 还很陌生,但很喜欢学习它。我真正苦苦挣扎的事情是将属性绑定到 DataTemplate 中的元素。

我创建了一个简单的 WPF 示例来(希望)解释我的问题。

在这个例子中,我试图将CheckBox 中的DataTemplateVisibility 属性绑定到我的视图模型中的属性。 (使用此场景纯粹用于学习/演示。)

我有一个名为 Item 的简单 DataModel,但在本示例中几乎没有相关性。

class Item : INotifyPropertyChanged


    // Fields...
    private bool _IsRequired;
    private string _ItemName;

还有一个相当简单的视图模型,名为 ItemViewModel。

class ItemViewModel : INotifyPropertyChanged

    private ObservableCollection<Item> _Items;
    private bool _IsCheckBoxChecked;
    private bool _IsCheckBoxVisible;

    public ObservableCollection<Item> Items
    
        get  return _Items; 
        set  _Items = value; 
    


    public bool IsCheckBoxChecked
    
        get  return _IsCheckBoxChecked; 
        set
        
            if (_IsCheckBoxChecked == value)
                return;
            _IsCheckBoxChecked = value;
            if (PropertyChanged != null)
            
                PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxChecked"));
                PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxVisible"));
            
        
    


    public bool IsCheckBoxVisible
    
        get  return !_IsCheckBoxChecked; 
        set
        
            if (_IsCheckBoxVisible == value)
                return;
            _IsCheckBoxVisible = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxVisible"));
        

(为简洁起见,省略了构造函数和INotifyPropertyChanged 实现。)

MainPage.xaml 中的控件布局如下。

<Window.Resources>
    <local:VisibilityConverter x:Key="VisibilityConverter"/>
</Window.Resources>

<Window.DataContext>
    <local:ItemViewModel/>
</Window.DataContext>

<Grid>
    <StackPanel>
        <CheckBox x:Name="checkBox" Content="Hide CheckBoxes"  FontSize="14"  IsChecked="Binding IsCheckBoxChecked, Mode=TwoWay" />
        <ListView ItemsSource="Binding Items" HorizontalContentAlignment="Stretch" >
            <ListView.ItemTemplate >
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Binding ItemName"/>
                        <CheckBox  Grid.Column="1" Visibility="Binding IsCheckBoxVisible, Converter=StaticResource VisibilityConverter"   >
                            <CheckBox.DataContext>
                                <local:ItemViewModel/>
                            </CheckBox.DataContext>
                        </CheckBox>
                    </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
       <StackPanel Orientation="Horizontal" Margin="4,4,0,0">
        <TextBlock Text="IsCheckBoxVisible:"/>
            <TextBlock Text="Binding IsCheckBoxVisible" Margin="4,0,0,0" FontWeight="Bold" />
        </StackPanel >
        <Button Content="Button" Visibility="Binding IsCheckBoxVisible, Converter=StaticResource VisibilityConverter" Margin="4,4,4,4"/>
    </StackPanel>

</Grid>

“隐藏复选框”复选框绑定到IsCheckBoxChecked,用于更新IsCheckBoxVisible。我还在DataTemplate 下方添加了几个额外的控件,以证明(对我自己)一切正常。)

我还实现了 Jeff Wilcox 的值转换器。 (谢谢。)http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

当我运行应用程序时,选中和取消选中“隐藏复选框”,DataTemplate 函数之外的控件按预期进行,但是,唉,数据模板内的Checkbox 保持不变。

我已经成功了:

IsVisible="Binding IsChecked, Converter=StaticResource VisibilityConverter, ElementName=checkBox"

但我不只是在尝试模仿另一个控件,而是根据一个值做出决定。

非常感谢您提供的任何帮助或建议。

谢谢。

【问题讨论】:

在 Visual Studio 的调试输出窗口中是否出现任何绑定错误?它们通常很好地表明出了什么问题。 克里斯。感谢您的回复。检查了输出窗口,正如您所怀疑的,有错误。它无法“找到”IsCheckBoxVisible。根据下面邓肯的回复应用了修复,现在一切都很好。谢谢。 这能回答你的问题吗? Binding to viewmodel from inside a datatemplate 【参考方案1】:

当您在 DataTemplate 中时,您的 DataContext 是数据模板对象,在本例中为 Item。因此,DataTemplate 中 CheckBox 的 DataContext 是 Item,而不是您的 ItemViewModel。您可以通过&lt;TextBlock Text="Binding ItemName"/&gt; 看到这一点,它绑定到Item 类的一个属性。与 IsCheckBoxVisible 的绑定正在尝试在 Item 上查找名为 IsCheckBoxVisible 的属性。

有几种方法可以解决这个问题,但到目前为止最简单的是这样做:

在您的窗口上(在 xaml 中),输入它和 x:Name。例如:

<Window [...blah blah...]
        x:Name="MyWindow">

将您的绑定更改为如下所示:

<CheckBox Grid.Column="1"
          Visibility="Binding DataContext.IsCheckBoxVisible, ElementName=MyWindow, Converter=StaticResource VisibilityConverter">

我们使用 Window 作为 Binding 的源,然后查看它的 DataContext 属性(应该是您的 ItemViewModel,然后关闭 IsCheckBoxVisible 属性。

如果您想要更高级的东西,另一种选择是使用代理对象来引用您的 DataContext。见this article on DataContextProxy。

【讨论】:

邓肯。感谢您的及时答复。我已经尝试过你的建议,它就像一个魅力。我认为为复选框添加一个单独的 标记会起作用,但唉,不行。再次感谢您。还将在您提供的链接中阅读 Dan Wahlin 的文章。 (我尝试投票支持你的答案,但我的低声望使我无法这样做。) 很高兴能帮上忙! :-) 这并不完全相关,但顺便说一句,您的评论:手动设置元素的 DataContext(窗口或其他根除外)是您需要非常小心的事情,并且通常表明您'做错事了。我想象你的尝试是沿着&lt;CheckBox.DataContext&gt;&lt;local:ItemViewModel/&gt;&lt;/...&gt; 的路线:如果是这样,它不起作用的原因是当你在 xaml 中定义 ItemViewModel 就像你 创建 一个,所以你' d 有不同的实例。您可以解决这个问题,但我描述的解决方案更好。

以上是关于绑定到 DataTemplate 中的视图模型属性的主要内容,如果未能解决你的问题,请参考以下文章

如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?

用于视图模型的具有多个 DataTemplate 的 ItemsControl

绑定视图 - 如何从子列表中获取父属性的详细信息

如何向上发送数据?从Datatemplate到上面

WPF 在 GridViewColumn.CellTemplate 的 DataTemplate 中绑定 UserControl 属性

在 DataTemplate 中使用时,行为 DependencyProperty 不更新 ViewModel