【问题标题】:Refreshing UI with databind in WPF在 WPF 中使用数据绑定刷新 UI
【发布时间】:2009-06-16 15:27:31
【问题描述】:

我有一个 3 层深的树视图,

-主要的 ->:SUB1 >:SUB2 >:SUB2 -X:SUB1 X:SUB2 SUB1 SUB1

其中,> 和 X 表示表示特定项目状态的图形(由后端确定)。

我正在使用 Observable Dictionary 绑定到这棵树(并且它有一个 ICollectionChanged 事件)。结构是这样的:

ObservableDictionary<string,CustomClass> mainitems; public class CustomClass{ ObservableDictionary<string, InnerClass> sub1item; // Bunch of properties and methods in this class // INotify not implemented } public class InnerClass{ // Bunch of properties and methods in this class // INotify not implemented public SomeEnum Status{ get{ return this.status; } } }

上面提到的图形是使用自定义转换器绑定的,该转换器将状态枚举转换为路径以便可以绑定(即。)。

问题:

我的问题是,当我用新状态更新 CustomClass 的 sub1item 字典时,它不会在 UI 中更新它。我认为实现 INotify 的东西可能会奏效,但我不知道我需要在哪里更新它以及具体如何更新。

编辑: 我的树视图的 XAML 模板如下:

<TreeView Name="tvInstance" ItemsSource="{Binding}" TreeViewItem.Selected="tviSelected" IsTextSearchEnabled="True"> <TreeView.ItemContainerStyle> <Style> <Setter Property="TreeViewItem.IsExpanded" Value="{Binding Path=Value.Expanded, Mode=TwoWay}" /> </Style> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Path=Value.CustomClass}" ItemContainerStyle="{x:Null}"> <StackPanel Orientation="Horizontal"> <Label Content="{Binding Path=Key}"/> </StackPanel> <HierarchicalDataTemplate.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Path=Value.AnotherClass}"> <StackPanel Orientation="Horizontal"> <Image Source="{Binding Path=Value.Status, Converter={StaticResource convertstatus} }" Width="10" Height="10"/> <Label Content="{Binding Path=Key}" /> </StackPanel> <HierarchicalDataTemplate.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="{Binding Path=Value, Converter={StaticResource convertstatus} }" Width="10" Height="10"/> <Label Content="{Binding Path=Key}" /> </StackPanel> </DataTemplate> </HierarchicalDataTemplate.ItemTemplate> </HierarchicalDataTemplate> </HierarchicalDataTemplate.ItemTemplate> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>

编辑:在我的主类、CustomClass 和 InnerClass 中添加所有 INotifyProperty 事件后,它仍然不起作用。我正在使用 ObservableDictionary 的 Dr. WPF 版本(并且使用字典对我的应用程序至关重要,因为我需要进行大量查找)。救命!

结语

此页面中的答案是正确的,因为我需要在 UI 中更新的属性上实现 INotifyPropertyChanged。

我发现绑定字典太麻烦了,所以我同时保留了 ObservableCollection 和字典。我使用字典进行查找,使用集合进行绑定(因为两者都使用对对象的相同引用,所以使用集合和唯一的 O(n) 操作很容易删除)。

关于UI的更新,请参考本页其他帖子。

【问题讨论】:

  • 您是否要重新实例化 sub1item 字典?如果是这样,那么您需要在包含它的类中实现 INotifyPropertyChanged。
  • CustomClass 有一个 Refresh() 方法设置 sub1item = new ObservableDictionary<..>();然后再次获取所有 InnerClass 项目。但是,它们几乎是相同的项目。我只想更新那些被改变的。 IE。渗透变化。
  • 你有没有找到解决这个问题的方法?
  • 赞成,因为您花时间写了那篇尾声。高五

标签: c# wpf data-binding


【解决方案1】:

这可能有点长,这是我的最佳猜测:

public class CustomClass : INotifyPropertyChanged
{
  public CustomClass()
  {
    sub1item = new ObservableDictionary<string, InnerClass>();
    // This next line may not be necessary... Changes might propogate up.
    sub1item.CollectionChanged += () => NotifyPropertyChange("Sub1Item");
  }

  private ObservableDictionary<string, InnerClass> sub1item;
  public ObservableDictionary<string, InnerClass> Sub1Item
  {
    get { return sub1item; }
    private set { sub1item = value; NotifyPropertyChange("Sub1Item"); }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  private void NotifyPropertyChanged(String info)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
  }
}

public class InnerClass : INotifyPropertyChanged
{
  public SomeEnum Status
  {
    get { return this.status; }
    private set { this.status = value; NotifyPropertyChange("Status"); }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  private void NotifyPropertyChanged(String info)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
  }
}

只需确保您通过调用 Status = something 来更新您的状态,而不是直接通过 this.status 来更新您的状态

编辑:如果您只想更新获得更新状态的单个对象,我不确定这是否会做到。我怀疑这将表明 Sub1Item 已更改,但 mainitems 可能不知道单个对象。这取决于您的实施。

如果您为 CustomClass 创建了一个 DataTemplate,它与 Sub1Item 绑定,那么您的绑定将仅针对更新后的状态正确更新

<DataTemplate DataType="{x:Type myClrNamespace:InnerClass}">
    <Grid>
        <TextBlock Text={Binding Path=Status}/>
    </Grid>
</DataTemplate>
...
<ListBox x:Name="listStatus"/>

然后在某处的 C# 中,您可能有:listStatus = mainlist[0].Sub1Item; 在看到您的 TreeView ItemTemplate 示例之后,我不确定了。

【讨论】:

  • 除了添加 sub1item.CollectionChanged +=... 行(由于我的 Dictionary 的 CollectionChanged 事件受到保护,我不能这样做)之外,我已经尝试了所有方法。另外,我注意到您使用了 NotifyChange 和 NotifyPropertyChanged,我认为它们是相同的......还有其他想法吗?
【解决方案2】:

可观察集合实现INofityCollectionChanged,WPF 使用它来刷新视图项的集合。

但是,要更新状态,您需要您的数据来实现INotifyPropertyChanged

  • 您希望出现在视图中的每个类都必须实现它,因此 WPF 将知道其属性何时更改以及哪些属性已更改。

实现很简单……

// Should implement INotifyPropertyChanged if the dictionary itself
// can be changed and not only its items
public class CustomClass {
    ObservableDictionary sub1item;
    // Bunch of properties and methods in this class
    // INotify not implemented
}


public class InnerClass : INotifyProperyChanged {
    // Bunch of properties and methods in this class
    // INotify not implemented
    public SomeEnum Status{
        get{ return this.status; }
    }

    public event PropertyChangedEventHandler PropertyChanged;



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


// where ever this.status is changed directly,
// call NotifyPropertyChanged("Status")
// (at end of that method)
//
// if this.status is changed from outside class (if public),
// then add a public method NotifyStatusChanged() which calls
// NotifyPropertyChanged("Status")
//
// If Status property has a set{} then if new value != this.status,
// call NotifyPropertyChanged("Status") at end of setter

}

【讨论】:

    【解决方案3】:

    你需要使用一个事件,让你的类实现 INotifyPropertyChanged,它看起来像这样:

    public class InnerClass: INotifyPropertyChanged
    {
         private string _propertyName;
    
         //Implemented from INotifyPropertyChanged
         public event PropertyChangedEventHandler PropertyChanged;
    
         public string PropertyName
         {
            get { return _propertyName; }
            set 
            { 
                  _propertyName = value;
                  OnPropertyChanged("Name or Property Data"); 
            }
         }
    
         //Just using string as an example, send whatever data you'd like
         protected void PropertyChanged(string name)
         {
            //Check to make sure the event is wired.
            if(PropertyChanged != null)
            {
                  //Fire event
                  PropertyChanged(this, name);
            }
         }
    }
    

    基本上,让这些事件为您的子项目触发并传递给您的 CustomClass 对象。然后,如果需要,让 CustomClass 处理这些事件,并触发另一个事件到您的主对象,告诉它更新 UI。

    【讨论】:

      【解决方案4】:

      ObservableDictionary(Of TKey, TValue) - VB.NET

      一般功能列表:

      • ObservableDictionary(Of TKey, TValue)
      • AddRange 只收到一次通知。
      • 通用 EventArgs(Of TKey, TValue)
      • NotifyDictionaryChanging(Of TKey, TValue) - CancelEventArgs 的子类,允许取消操作。

      【讨论】:

        【解决方案5】:

        “任务”类的工作示例

        公共类任务:INotifyPropertyChanged

        {
        
            //Implemented from INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
        
            private void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
        

        私有字符串文本;

            public string Text
            {
                get { return text; }
                set { 
                    text = value;
                    NotifyPropertyChanged("Text");
        
                    }
            }
        

        }

        另一方面,值得记住的是,当数据绑定到类型集合时,您需要使用 ObservableCollection 而不是 List 来获取动态更新的 ItemSource。列表不通知。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-28
          • 2014-06-25
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多