c# - 如果 ObservableCollection,绑定(bind)到文本框的列表将不会更新

标签 c# wpf xaml

我正在 WPF 中创建自定义控件。我绑定(bind)一个List<IMyInterface>dependency property .这又再次绑定(bind)到 ListBox按预期显示所有项目。

我现在想将此列表中的 1 项绑定(bind)到 Textblock ,所以我将整个列表绑定(bind)到 textblock .我有一个 converter在此提取我想要的单个项目。

它运行良好,但出于一些原因,我想使用 ObservableCollection而不是 List

奇怪的是,当我更改 ObservabaleCollection 中的值时在运行时,该值显示在 ListBox 中(成功)但不在我的textblock . converter甚至没有被击中!

    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));
    }

xaml 很简单

 <local:Notify Events="{Binding Errors}" DockPanel.Dock="Right"/>

如您所见,我已尝试使用 CollectionChanged事件然后强制触发 INotifyPropertyChanged , 但它在我的 Converter 中触发然而ListBox正在更新(所以我知道绑定(bind)没问题)

这是 UserControls xaml

 <TextBlock Text="{Binding Path=Events, RelativeSource={RelativeSource AncestorLevel=1, AncestorType=UserControl}, Mode=Default, Converter={StaticResource MostRecentConverter}}" Grid.Row="0" />

    <ListBox ItemsSource="{Binding Path=Events, RelativeSource={RelativeSource AncestorLevel=1,AncestorType=UserControl}, Mode=Default}" Grid.Row="1">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding EventTitle}" Style="{StaticResource txtBckRed}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

我还需要做其他事情吗?

最佳答案

如评论中所述TextBlock只绑定(bind)到Events属性更改(不是它的项目),因此除非创建新的集合实例,否则它不会触发。对 INotifyCollectionChanged 作出 react 是 ItemsSource 的特征属性(property)。

解决方案一

暂时保留所有内容,只需提供 TextBlock一些名字

<TextBlock Text="{Binding ...}" x:Name="myTextBlock"/>

并订阅CollectionChanged你里面的事件UserControl您手动强制绑定(bind)目标更新的地方

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); }
    }

}

方案二

创建你自己的集合类继承自ObservableCollection<T>具有可以执行您的转换器所做的自定义属性

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"));
        }
    }
}

并绑定(bind)TextBlock.TextEvents.ConvertedText属性代替,不需要转换器

关于c# - 如果 ObservableCollection,绑定(bind)到文本框的列表将不会更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36661607/

相关文章:

c# - 为什么这个对象在浅拷贝后不为空?

c# - Linq.Except的更多 "SQL-syntax"

wpf - 异常 : 'IValueConverter' type does not have a public TypeConverter class

WPF 在其他 ControlTemplates 中重用模板

c# - WPF - 对许多元素产生相同的效果

c# - 使用 XamlReader.Parse() 从字符串读取 xaml 时使用转换器

wpf - 如何用网格填充数据网格文本列标题中的所有空间?

c# - 撤消 DbContext.Add()

c# - Fluent NHibernate MySQL 批处理

c# - 如何获取滚动查看器的可滚动高度以在交互请求中更新