C# 将列表绑定到文本框赢得';如果可观察到收集,则不更新
我正在WPF中创建一个自定义控件。我将C# 将列表绑定到文本框赢得';如果可观察到收集,则不更新,c#,wpf,xaml,C#,Wpf,Xaml,我正在WPF中创建一个自定义控件。我将列表绑定到依赖项属性。这反过来又绑定到一个列表框,该列表框按预期显示所有项目 现在我想将此列表中的一项绑定到Textblock,因此我将整个列表绑定到Textblock。我有一个转换器,可以提取我想要的单个项目 它工作得很好,但出于几个原因,我想使用observeablecollection而不是List 奇怪的是,当我在运行时更改我的observabalcollection中的值时,该值会显示在列表框中(成功),但不会显示在我的文本块中。转换器甚至没有被击
列表
绑定到依赖项属性
。这反过来又绑定到一个列表框
,该列表框按预期显示所有项目
现在我想将此列表中的一项绑定到Textblock
,因此我将整个列表绑定到Textblock
。我有一个转换器
,可以提取我想要的单个项目
它工作得很好,但出于几个原因,我想使用observeablecollection
而不是List
奇怪的是,当我在运行时更改我的observabalcollection
中的值时,该值会显示在列表框中(成功),但不会显示在我的文本块中。转换器
甚至没有被击中
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.Errors = new ObservableCollection<IEventDetail>();
this.Errors.CollectionChanged += Errors_CollectionChanged;
var bw = new BackgroundWorker();
bw.DoWork += ((o, e) =>
{
System.Threading.Thread.Sleep(1500);
Dispatcher.Invoke(() =>
{
this.Errors.Add(new MyEvents("example of some detail", "Failed title"));
});
System.Threading.Thread.Sleep(2500);
Dispatcher.Invoke(() =>
{
this.Errors.Add(new MyEvents("Another example", "Failed title 2"));
});
});
bw.RunWorkerAsync();//background worker for testing/debugging only
}
private void Errors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("Errors");
}
private ObservableCollection<IEventDetail> _errors;
public ObservableCollection<IEventDetail> Errors
{
get
{
return this._errors;
}
set
{
this._errors = value;
OnPropertyChanged("Errors");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
是否需要执行其他操作?如注释TextBlock
it中所述,它只绑定到事件属性更改(不是它的项)
,因此除非创建新的集合实例,否则它不会触发。对INotifyCollectionChanged
作出反应是ItemsSource
属性的特征
解决方案1
让一切保持现状,只需给TextBlock
一些名字
<TextBlock Text="{Binding ...}" x:Name="myTextBlock"/>
解决方案2
使用自定义属性创建您自己的集合类,该类继承自ObservableCollection
,该属性将执行转换器所执行的操作
public class MyObservableCollection<T> : ObservableCollection<T>
{
private string _convertedText;
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
this.ConvertedText = ...; // <- do here what your IValueConverter does
}
public string ConvertedText
{
get { return _convertedText; }
private set
{
_convertedText = value;
OnPropertyChanged(new PropertyChangedEventArgs("ConvertedText"));
}
}
}
公共类MyObservableCollection:ObservableCollection
{
私有字符串_convertedText;
CollectionChanged上的受保护覆盖无效(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
基础。变更的集合(e);
this.ConvertedText=…;//问题必须在xaml上,onpropertychanged在observableCollection中是隐式的。(您能发布xaml吗?)尝试设置explicti双向绑定和UpdataSourceTrigger=PropertyChanged@Xilmiki,谢谢,但是,绑定正在列表框
,而不是文本块
。所以我不确定为什么我需要双向绑定,或者甚至使用UpdateSourceTrigger
请尝试设置显式双向绑定和UpdateSourceTrigger=Pro文本框绑定中的pertychange,我在我的WPF项目中遇到了相同的问题。@Dave itTextBlock
它只绑定到Events
属性更改(不是它的项)因此,除非创建新集合,否则它不会触发。即使手动引发错误的属性更改事件
,也不会起作用,因为UI会看到集合实例实际上与INotifyCollectionChanged
相同,这是项资源
属性的特征。转换器做什么?您可以d基于添加自定义属性的observateCollection
创建集合类型,该属性执行转换器的操作,或者在用户控件中订阅CollectionChanged
事件,并手动刷新TextBlock
<TextBlock Text="{Binding ...}" x:Name="myTextBlock"/>
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty EventsProperty =
DependencyProperty.Register("Events",
typeof(IEnumerable),
typeof(MyUserControl),
new PropertyMetadata(EventsPropertyChanged));
private static void EventsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyUserControl)d).EventsPropertyChanged(e);
}
private void EventsPropertyChanged(DependencyPropertyChangedEventArgs args)
{
var newCollection = args.NewValue as INotifyCollectionChanged;
if (newCollection != null)
newCollection.CollectionChanged += (s, e) => myTextBlock.GetBindingExpression(TextBlock.TextProperty).UpdateTarget();
}
public IEnumerable Events
{
get { return (IEnumerable)GetValue(EventsProperty); }
set { SetValue(EventsProperty, value); }
}
}
public class MyObservableCollection<T> : ObservableCollection<T>
{
private string _convertedText;
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
this.ConvertedText = ...; // <- do here what your IValueConverter does
}
public string ConvertedText
{
get { return _convertedText; }
private set
{
_convertedText = value;
OnPropertyChanged(new PropertyChangedEventArgs("ConvertedText"));
}
}
}