【问题标题】:Updating the bindings of a DataTemplate within a DataTemplate在 DataTemplate 中更新 DataTemplate 的绑定
【发布时间】:2012-12-05 07:54:57
【问题描述】:

我有以下 xaml;

    <DataTemplate DataType="{x:Type NameSpace:Node}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Item.Value}"/>
            <ContentControl Content="{Binding Item}"/>
        </StackPanel>
    </DataTemplate>

    <DataTemplate DataType="{x:Type NameSpace:Item}">
        <TextBlock Text="{Binding Value}" />
    </DataTemplate>

当我使用 Node 模板显示 Node 对象时,我得到两个 TextBlock,它们都显示相同的值。到现在为止还挺好。项目更改时会出现问题。当 Node 类触发 INotifyPropertyChanged 事件时,Node DataTemplate 中的 TextBlock 会按预期更新,但 Item DataTemplate 中的 TextBlock 不会更新。

当 Node 类触发 IPropertyChanged 事件时,如何让 Item DataTemplate 更新其绑定?

更新 事实证明,上述方法适用于以下简单场景;

Xaml

        <DataTemplate DataType="{x:Type DataTemplateExample:Node}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Item.Value}"/>
                <ContentControl Content="{Binding Item}"/>
            </StackPanel>
        </DataTemplate>

        <DataTemplate DataType="{x:Type DataTemplateExample:Item}">
            <TextBlock Text="{Binding Value}" />
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <StackPanel Orientation="Vertical">
            <ContentControl Content="{Binding MyNode}"/>
            <Button Command="{Binding ChangeMyNodeItem}">Change Item</Button>
        </StackPanel>
    </Grid>
</Window>

c#

public class MainViewModel
{
    private readonly Node myNode;
    private readonly DelegateCommand changeMyNodeItemCmd;

    public MainViewModel()
    {
        myNode = new Node {Item = new Item("a")};
        changeMyNodeItemCmd = new DelegateCommand(()=>
            myNode.Item = new Item("b"));
    }

    public Node MyNode { get { return myNode; } }

    public ICommand ChangeMyNodeItem
    {
        get { return changeMyNodeItemCmd; }
    }
}

public class Node : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Item item;
    public Item Item
    {
        set
        {
            item = value;
            if (PropertyChanged != null)
                PropertyChanged(this,new PropertyChangedEventArgs("Item"));
        }
        get { return item; }
    }
}

public class Item
{
    private readonly string value;

    public Item(string value)
    {
        this.value = value;
    }

    public string Value
    {
        get { return value; }
    }
}

在我的真实场景中,我使用了代理,我认为这就是让 WPF 感到困惑的原因。项目实际上并没有改变 - 它正在重新映射。

最终我使用类似于 ShadeOfGray 提出的解决方案解决了这个问题。但我应该指出,除非您使用代理,否则这不是必需的。

【问题讨论】:

  • 我假设您已经拥有 INotifyPropertyChanged 离子您的 Item 类,以便查看值更改。您是否还在节点类上实现 INotifyPropertyChanged?如果不是,ContentControl 将保持绑定到旧项目。
  • 我已经在我的 Node 类中实现了 INotifyPropertyChanged,以便在 Item 属性更改时进行。我没有在我的 Item 类中实现 INotifyPropertyChanged,因为这个类是不可变的。对于 Item 的特定实例,Value 属性永远不会改变。它是可变的节点类,我希望在重新分配 Node.Item 时更新 UI。

标签: wpf data-binding


【解决方案1】:

根据您发布的内容,我认为您在错误的类中触发了 NotifyPropertyChanged。类似的东西应该在您的场景中正常工作。

根据评论更新:

public class Node : INotifyPropertyChanged
{
    private Item item;

    public event PropertyChangedEventHandler PropertyChanged;

    public Item Item
    {
        get
        {
            return item;
        }

        set
        {
            item = value;

            this.NotifyPropertyChanged("Item");

            if (item != null)
            {
                item.ForcePropertyChanged("Value");
            }
        }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class Item : INotifyPropertyChanged
{
    private string itemValue;

    public Item()
    {
        this.Value = string.Empty;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public string Value
    {
        get
        {
            return itemValue;
        }

        set
        {
            itemValue = value;

            NotifyPropertyChanged("Value");
        }
    }

    public void ForcePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

【讨论】:

  • 感谢您的回复。您发布的代码涵盖了直接更改 Value 属性的场景...例如:myNode.Item.Value = newValue; 我感兴趣的场景是通过重新分配父级间接更改 Value... 例如:myNode.Item = new Item { Value = newValue };
  • 是的,这看起来像是一个潜在的解决方案 - 谢谢!我希望 WPF 可能足够聪明,可以为我解决这个问题,但如果在 xaml 中无法做到这一点,我将使用此解决方案。我的 Item 类实际上是不可变的,所以让它触发 INotifyPropertyChanged 事件感觉不太对。
  • 还有一件事。如果 Node 对象的集合是 ObservableCollection,您可以完全删除 ForcePropertyChanged 属性。
猜你喜欢
  • 2011-12-30
  • 1970-01-01
  • 2022-10-24
  • 2013-01-14
  • 2013-05-29
  • 2012-07-14
  • 2017-08-26
  • 2011-05-11
相关资源
最近更新 更多