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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15748578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:45:08  来源:igfitidea点击:

Binding to a viewmodel property in a DataTemplate

wpfxamlpropertiesbindingdatatemplate

提问by Dowse

I'm fairly new to XAML but enjoying learning it. The thing I'm really struggling with is binding a property to an element in a DataTemplate.

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

I have created a simple WPF example to, (hopefully,) explain my problem.

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

I this example I am trying to bind the Visibilityproperty of a CheckBoxin a DataTemplateto a Property in my viewmodel. (Using this scenario purely for learning/demo.)

在这个例子中,我试图将VisibilityaCheckBox中的属性绑定DataTemplate到我的视图模型中的属性。(使用这个场景纯粹是为了学习/演示。)

I have a simple DataModel named Item, but is of little relevance in this example.

我有一个名为 的简单数据模型Item,但与本示例无关。

class Item : INotifyPropertyChanged
{

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

And a fairly simple View Model named ItemViewModel.

还有一个相当简单的视图模型,名为 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"));
        }

(Constructors and INotifyPropertyChangedimplementation omitted for brevity.)

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

Controls laid out in MainPage.xaml as follows.

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>

The 'Hide CheckBoxes' checkbox is bound to IsCheckBoxCheckedand is used to update IsCheckBoxVisible. I've also added a couple of extra controls below the DataTemplateto prove, (to myself,) the everything works.)

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

I have also implemented Jeff Wilcox's value converter. (Thank you.) http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

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

When I run the app, checking and unchecking the 'Hide Checkbox', controls outside the DataTemplatefunction as expected but, alas, the Checkboxinside the data template remains unchanged.

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

I have had success with:

我在以下方面取得了成功:

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

But I'm not just trying mimic another control but make decisions based on a value.

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

I would REALLY appreciate any help or advice you can offer.

我真的很感激你能提供的任何帮助或建议。

Thank you.

谢谢你。

回答by Duncan Matheson

When you are in a DataTemplate, your DataContext is the data templated object, in this case an Item. Thus, the DataContext of the CheckBox in the DataTemplate is an Item, not your ItemViewModel. You can see this by your <TextBlock Text="{Binding ItemName}"/>, which binds to a property on the Itemclass. The Binding to IsCheckBoxVisible is trying to find a property called IsCheckBoxVisible on Item.

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

There are a couple of ways around this, but by far the easiest is to do this:

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

On your Window (in the xaml), give it and x:Name. Eg:

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

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

Change your binding to look like this:

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

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

We're using the Window as the source for the Binding, then looking at its DataContext property (which should be your ItemViewModel, and then pulling off the IsCheckBoxVisible property.

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

Another option, if you want something fancier, is to use a proxy object to reference your DataContext. See this article on DataContextProxy.

如果您想要更高级的东西,另一种选择是使用代理对象来引用您的 DataContext。请参阅有关 DataContextProxy 的这篇文章