C# 在WPF中使用数据绑定刷新UI
我有一个三层深的树景 -MAIN ->:SUB1 >:SUB2 >:SUB2 -X:SUB1 X:SUB2 SUB1 SUB1 -主要 ->:SUB1 >:SUB2 >:SUB2 -X:SUB1 X:SUB2 SUB1 SUB1 其中,>和X表示表示表示该特定项目状态的图形(从后端确定) 我正在使用一个可观察字典绑定到此树(它有一个ICollectionChanged事件)。结构如下:C# 在WPF中使用数据绑定刷新UI,c#,wpf,data-binding,C#,Wpf,Data Binding,我有一个三层深的树景 -MAIN ->:SUB1 >:SUB2 >:SUB2 -X:SUB1 X:SUB2 SUB1 SUB1 -主要 ->:SUB1 >:SUB2 >:SUB2 -X:SUB1 X:SUB2 SUB1 SUB1 其中,>和X表示表示表示该特定项目状态的图形(从后端确定) 我正在使用一个可观察字典绑定到此树(它有一个ICollectionChanged事件)。结构如下: ObservableDictionary<string,CustomClas
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; }
}
}
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{
观察医学分项;
//该类中的一组属性和方法
//INotify没有实现
}
公共类内部类{
//该类中的一组属性和方法
//INotify没有实现
公共枚举状态{
获取{返回this.status;}
}
}
上面提到的图形是使用自定义转换器绑定的,该转换器将状态枚举转换为路径,以便可以绑定(即)
问题:
我的问题是,当我用新状态更新CustomClass的sub1item字典时,它不会在UI中更新它。我认为实现INotify可能会起作用,但我不知道我需要在哪里更新它,以及具体如何更新
编辑:
我的treeview的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>
编辑:在我的Main类、CustomClass和InnerClass中添加所有INotifyProperty事件后,它仍然不起作用。我使用的是Dr.WPF版本的Observatedictionary(使用字典对我的应用程序至关重要,因为我需要进行大量查找)。救命啊
后记
此页面中的答案是正确的,因为INotifyPropertyChanged需要在我希望在UI中更新的属性上实现
我发现装订这本词典太麻烦了,所以我保存了一本可观察的集和一本词典。我使用字典进行查找,使用集合进行绑定(因为两者都使用对对象的相同引用,所以使用集合和唯一的O(n)操作很容易删除)
关于UI中的更新,请参阅本页的其他帖子。这可能有点长,以下是我的最佳猜测:
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));
}
}
}
公共类CustomClass:INotifyPropertyChanged
{
公共自定义类()
{
sub1item=新的可观察药物();
//下一行可能没有必要…可能会出现更改。
sub1item.CollectionChanged+=()=>NotifyPropertyChange(“sub1item”);
}
私人医疗子项目;
公共医疗子项目
{
获取{return sub1item;}
私有集{sub1item=value;NotifyPropertyChange(“sub1item”);}
}
公共事件属性更改事件处理程序属性更改;
私有void NotifyPropertyChanged(字符串信息)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(信息));
}
}
}
公共类InnerClass:INotifyPropertyChanged
{
公共枚举状态
{
获取{返回this.status;}
私有集{this.status=value;NotifyPropertyChange(“status”);}
}
公共事件属性更改事件处理程序属性更改;
私有void NotifyPropertyChanged(字符串信息)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(信息));
}
}
}
只要确保通过调用status=something来更新状态,而不是直接通过this.status
编辑:如果您只想更新获得更新状态的单个对象,我不确定这样做是否可行。我怀疑这将表明Sub1Item已更改,但mainitems可能不知道单个对象。这取决于您的实现
如果您为CustomClass创建了一个DataTemplate,该DataTemplate绑定到Sub1Item,那么您的绑定将仅正确更新更新状态
<DataTemplate DataType="{x:Type myClrNamespace:InnerClass}">
<Grid>
<TextBlock Text={Binding Path=Status}/>
</Grid>
</DataTemplate>
...
<ListBox x:Name="listStatus"/>
...
然后在C#某处,您可以有:
listStatus=mainlist[0]代码>在看到您的TreeView ItemTemplate示例后,我再也不确定了。您需要使用一个事件,让您的类实现INotifyPropertyChanged,它将如下所示:
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; }
}
}
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 可观察集合实现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
}
-VB.NET
一般功能列表:
- 可观测的(TKey、TValue的)
- AddRange只收到一次通知
- 通用事件参数(属于TKey、TValue)
- NotifyDictionaryChangeg(TKey,TValue)——CancelEventArgs的一个子类,允许取消操作
类型为“任务”的类的工作示例
公共类任务: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而不是than List来获取动态更新的ItemSource。列表