简体   繁体   中英

WPF. Binding inside listbox itemtemplate to ObservableCollection source. Source PropertyChanged is ignored

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

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 derived from TextBlock. This class has one dependency property that I'm trying to bind to ObservableCollection in Model. ,我试图将其绑定到 ObservableCollection。

The problem is that changes in don't notify my about PropertyChanged event.中的更改不会将 PropertyChanged 事件通知我的Binding is functioned just once at object creation time and never after. object 创建时运行一次,此后便不再运行。

Any ideas why?

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

      
    }

Model class

    public class TextBlockModel
    {

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

ViewModel with collection for ListBox ItemSource

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

Test project here

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM