WPF.将列表框itemtemplate内部绑定到ObservableCollection源.源PropertyChanged被忽略 [英] WPF. Binding inside listbox itemtemplate to ObservableCollection source. Source PropertyChanged is ignored

查看:64
本文介绍了WPF.将列表框itemtemplate内部绑定到ObservableCollection源.源PropertyChanged被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个显示格式化文本的ListBox.我希望能够从代码更改格式.

I'm trying to create a ListBox that displays formatted text. I want to be able to change formatting from code.

为了显示格式化的文本,我选择了TextBlock,并打算使用TextBlock.Inlines集合进行格式化.TextBlock.Inlines是不可绑定的,因此我创建了从TextBlock派生的新类 BindableTextBlock .此类具有一个依赖项属性 InlineList ,我试图将其绑定到模型中的 InlinesColl ObservableCollection.

For displaying formatted text I chose TextBlock and intend to use the TextBlock.Inlines collection for formatting. TextBlock.Inlines is not bindable so I created new class BindableTextBlock derived from TextBlock. This class has one dependency property InlineList that I'm trying to bind to InlinesColl ObservableCollection in Model.

问题是 InlinesColl 中的更改不会通知我的 InlineList 关于 PropertyChanged 事件.绑定仅在 BindableTextBlock 对象创建时起作用一次,而从此以后就不会起作用.

The problem is that changes in InlinesColl don't notify my InlineList about PropertyChanged event. Binding is functioned just once at BindableTextBlock object creation time and never after.

有什么想法吗?

XAML:

                <ListBox  x:Name="PART_lb" VerticalAlignment="Stretch" ItemsSource="{Binding ItemColl}"
                            ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                            ScrollViewer.VerticalScrollBarVisibility="Auto" >
                    
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <local:BindableTextBlock InlineList="{Binding Path=InlinesColl}" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                    
                </ListBox>

BindableTextBlock类:

BindableTextBlock class:

 public class BindableTextBlock : TextBlock
    {
        public ObservableCollection<Inline> InlineList
        {
            get { return (ObservableCollection<Inline>)GetValue(InlineListProperty); }
            set { SetValue(InlineListProperty, value); }
        }

        public static readonly DependencyProperty InlineListProperty =
            DependencyProperty.Register("InlineList", typeof(ObservableCollection<Inline>), typeof(BindableTextBlock), new UIPropertyMetadata(null, OnPropertyChanged));

        private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            BindableTextBlock textBlock = (BindableTextBlock)sender;
            textBlock.Inlines.Clear();
            textBlock.Inlines.AddRange((ObservableCollection<Inline>)e.NewValue);
        }

      
    }

模型类

    public class TextBlockModel
    {

        ObservableCollection<Inline> _inlinesColl = new ObservableCollection<Inline>();
        public ObservableCollection<Inline> InlinesColl
        {
            get { return _inlinesColl; }
            set {_inlinesColl = value; }
        }
    }

具有用于ListBox ItemSource的集合的ViewModel

ViewModel with collection for ListBox ItemSource

        ObservableCollection<TextBlockModel> _itemColl = new ObservableCollection<TextBlockModel>();
        public ObservableCollection<TextBlockModel> ItemColl
        {
            get { return _itemColl; }
            set { _itemColl = value; }
        }

测试项目此处

推荐答案

以您的情况为例-当集合中的项目添加\删除时,您无法处理情况
当需要分配新的收藏集时,需要深入研究并订阅CollectionChanged.

In your case - you didn't handle case when item inside collection added\deleted
Need go deeply and subscirbe to CollectionChanged when new collection will be assigned.

 public class BindableTextBlock : TextBlock
    {
        static int Cntr = 0;
        public BindableTextBlock()
        {
            Console.WriteLine("BindableTextBlock constructor " + Cntr);
            Cntr++;
        }

        public ObservableCollection<Inline> InlineList
        {
            get { return (ObservableCollection<Inline>)GetValue(InlineListProperty); }
            set { SetValue(InlineListProperty, value); }
        }

        public static readonly DependencyProperty InlineListProperty =
            DependencyProperty.Register("InlineList", typeof(ObservableCollection<Inline>), typeof(BindableTextBlock), new UIPropertyMetadata(null, OnPropertyChanged));

        private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            BindableTextBlock textBlock = (BindableTextBlock)sender;

            // subscribe to collection changed
            textBlock.UpdateInlineListSource((ObservableCollection < Inline > )e.OldValue, (ObservableCollection < Inline > )e.NewValue);

        }

        public void UpdateInlineListSource(ObservableCollection<Inline> oldCollection, ObservableCollection<Inline> newCollection)
        {
            if (oldCollection!=null)
            oldCollection.CollectionChanged -= OnCollectionChanged;

            if (newCollection != null)
            {
                newCollection.CollectionChanged += OnCollectionChanged;
                OnCollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                OnCollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newCollection));
            }
        }

        private void OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            var newItems = e.NewItems?.Cast<Inline>()?.ToList() ?? new List<Inline>();
            var oldItems = e.OldItems?.Cast<Inline>()?.ToList() ?? new List<Inline>();

            // changed source
            if (e.Action==NotifyCollectionChangedAction.Reset)
                this.Inlines.Clear();

            foreach (var itemForDelete in oldItems)
            {
                if (this.Inlines.Contains(itemForDelete))
                    this.Inlines.Remove(itemForDelete);
            }

            foreach (var itemsForAdd in newItems)
            {
                this.Inlines.Add(itemsForAdd);
            }
        }
    }

这篇关于WPF.将列表框itemtemplate内部绑定到ObservableCollection源.源PropertyChanged被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆