【问题标题】:WPF TreeView Binding not updating the ViewWPF TreeView 绑定不更新视图
【发布时间】:2021-02-01 12:34:01
【问题描述】:

INotifyPropertyChanged 已实现,DataContext 已设置。

这是我的树视图:

    <TreeView ItemContainerStyle="{StaticResource MaterialDesignTreeViewItemExtended}" x:Name="TestCasesTree" MinWidth="220" ItemsSource="{Binding TestCases.Children, Mode=TwoWay}">
    <i:Interaction.Behaviors>
        <behaviours:BindableSelectedItemBehavior SelectedItem="{Binding SelectedTreeViewItem, Mode=TwoWay}" />
    </i:Interaction.Behaviors>
    <TreeView.Resources>
        <con:TestAssessmentToImagePathConverter x:Key="TestAssessmentConverter" />
    </TreeView.Resources>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=TwoWay}" DataType="{x:Type data:TestCaseNode}">
            <StackPanel Margin="0" Orientation="Horizontal">
                <Image Source="{Binding TestAssessment, Converter={StaticResource TestAssessmentConverter}}" RenderOptions.BitmapScalingMode="HighQuality" Width="20" Height="20"/>
                <TextBlock Margin="8 2 0 0" Text="{Binding Name}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

绑定:

ItemsSource="{Binding TestCases.Children, Mode=TwoWay}"

BindableBase 类:

public abstract class BindableBase : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected bool CanExecute
    {
        get
        {
            return true;
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

属性:

    public TestCaseNode TestCases
    {
        get { return mainWindowModel.TestCases; }
        set
        {
            mainWindowModel.TestCases = value;
            SetProperty(ref _testCases, value);
        }
    }

孩子们:

public ObservableCollection<TestCaseNode> Children { get; set; }

我编辑东西的地方:

 SelectedTreeViewItem.SetTestAssessmentForCluster(testAssessment);
 OnPropertyChanged("Children");   
 OnPropertyChanged("TestCases");
 OnPropertyChanged(nameof(TestCases));
 OnPropertyChanged(nameof(TestCases.Children));

View 中没有任何变化(但是当我在 Visual Studio 中调试它时,我清楚地看到对象发生了变化)

这可行,但它会导致其他事情崩溃:

SelectedTreeViewItem.SetTestAssessmentForCluster(testAssessment);
var tc = TestCases;
TestCases = null;
TestCases = tc;

更新:

TestCaseNode 类:

public class TestCaseNode : TestCase, IEquatable<TestCaseNode>, IComparable<TestCaseNode>
{
    public TestCaseNode Parent { get; set; }
    public ObservableCollection<TestCaseNode> Children { get; set; }

    public void Add(TestCaseNode node) {...}
    public void SetTestAssessmentForCluster(TestAssessment testAssessment, ref TestScores _testScores) {...}
    public bool Equals(TestCaseNode other) {...}
    public override bool Equals(object obj) {...}
    public override int GetHashCode() {...}
    public int CompareTo(TestCaseNode other) {...}
}

TestCase 类:

public class TestCase
{
    public string Id { get; set; } = string.Empty;
    public string Name { get; set; }
    public string Description { get; set; }
    public ObservableCollection<TestStep> TestSteps { get; set; }
    public TestAssessment TestAssessment { get; set; } = TestAssessment.EMPTY;
}

【问题讨论】:

  • 我认为 OnPropertyChanged("Children"); 需要从 TestCaseNode 类中调用 - 这就是 ObservableCollection&lt;TestCaseNode&gt; Children 所在的位置 - 是吗?
  • 所以我需要从 TestCaseNode 派生 BindableBase 类?好的,我试试看。
  • 所以我在 TestCaseNode 中派生了 BindableBase 并将 OnPropertyChanged("Children") 放在 SetTestAssessmentForCluster 方法的末尾 - 它不起作用。
  • 不是从 BindableBase 派生的。包含 ObservableCollection&lt;TestCaseNode&gt; Children' must include the OnPropertyChanged("Children");` 调用的对象。也就是说,OnPropertyChanged("Children"); 调用必须由TestCases 类发出。请调整您的问题以包含更多此类内容。

标签: c# xaml mvvm


【解决方案1】:

OnPropertyChanged("TestCases"); 必须由包含已更改属性的对象发出。在您的情况下,您的类 TestCaseNode 将需要调用 OnPropertyChanged 方法,以便 Treeview 识别对集合的更改,因为该对象包含集合。也就是说,更改的不仅仅是名为"TestCases" 的任何属性,而是特定对象中的属性。原因:您可以在不同的类中拥有多个具有此名称的属性。而且,如果对象有多个副本,则它们每个副本都有一个同名的属性。

我所做的,这对我有用,是在 TestCaseNode 中添加一个名为 UpdateProperties() 的公共方法,然后调用 OnPropertyChanged("TestCases"); 这确保属性更新由正确的对象发出。然后在需要更新控件时调用此方法。

还有其他几种方法可以做同样的事情,但我发现这是一种简单直接的方法。例如,您可以包括 `OnPropertyChanged("TestCases");在您的添加方法中。我没有这样做是因为 1) OnPropertyChanged 调用发生得太频繁,并且 2) 如果没有 OnPropertyChanged 调用,我可以推迟对控件的更新,直到我完成了几个或全部 Add 之后。

【讨论】:

  • 所以我需要在TestCaseNode 类中实现INotifyPropertyChanged?或者我可以从已经实现该接口的BindableBase 派生,然后在TestCaseNode 中调用OnPropertyChanged
  • 由于TestCaseNode 已经派生自TestCase,它不能派生自另一个类。你可以让TestCase 派生自BindableBase,或者你可以只实现INotifyPropertyChanged。根据我的阅读,您应该坚持使用INotifyPropertyChanged,但是,无论哪种方式都没有明确的证据。
  • 我在TestCaseNode 中派生了BindableBase,并将OnPropertyChanged("Children") 放在更改Children 属性的方法的末尾。视图仍未更新。
  • 您仍然需要显式调用OnPropertyChanged 您对集合的更改不会导致通过属性发生这种情况。
  • 我明白了。我在更改属性的方法中调用OnPropertyChanged
猜你喜欢
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 2010-12-26
  • 2020-09-21
  • 1970-01-01
  • 2013-10-31
相关资源
最近更新 更多