绑定到DataTemplate中的ViewModel属性

12

我对XAML还比较陌生,但很喜欢学习它。我真正遇到困难的是将属性绑定到DataTemplate中的元素。

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

在这个示例中,我试图将DataTemplate中的CheckBoxVisibility属性绑定到我的视图模型中的属性。(仅用于学习/演示场景)

我有一个名为Item的简单数据模型,但在本示例中并不太相关。

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"));
        }
< p >(出于简洁起见,构造函数和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的调试输出窗口里有没有出现任何绑定错误?它们通常是问题出在哪里的很好的提示。 - ChrisF
Chris。感谢您的回复。我检查了输出窗口,正如您所怀疑的那样,出现了错误。它无法“找到”IsCheckBoxVisible。按照Duncan在下面的回复中提供的修复方法进行了修复,现在一切都很好。谢谢。 - Dowse
这个回答解决了你的问题吗?从数据模板内部绑定到ViewModel - StayOnTarget
1个回答

28
当您在DataTemplate中时,您的DataContext是数据模板化对象,即一个Item。因此,在DataTemplate中的CheckBox的DataContext是一个Item,而不是您的ItemViewModel。您可以通过TextBlock Text="{Binding ItemName}"看到这一点,它将绑定到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}}">

我们将窗口用作绑定的源,然后查看其DataContext属性(应该是您的ItemViewModel),再获取IsCheckBoxVisible属性。

如果您想要更加复杂的选项,另一个选择是使用代理对象引用您的DataContext。请参见DataContextProxy上的文章


1
Duncan。感谢您的及时回复。我尝试了您的建议,它非常有效。我原本以为为复选框添加单独的<DataContext>标签会起作用,但是不行。再次感谢您。我也会阅读您提供的链接中Dan Wahlin的文章。 (我尝试投票支持您的答案,但我的声望太低了,无法这样做。) - Dowse
很高兴能帮到你! :-) 虽然这不完全相关,但是从你的评论中可以看出:手动设置元素(除了窗口或其他根元素)的DataContext是需要非常小心的,并且通常意味着你正在做一些错误的事情。我想象你的尝试是类似于 <CheckBox.DataContext><local:ItemViewModel/></...> 的:如果是这样,它不能工作的原因是当你在xaml中定义ItemViewModel时,你正在创建一个实例,所以你会有一个不同的实例。你可以解决这个问题,但我描述的解决方案更好。 - Duncan Matheson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接