JokerMartini
JokerMartini

Reputation: 6147

wpf INotifyCollectionChanged redundancy

I've written a custom control and I have two collection dependency properties SourceA and SourceB. You'll see in the code below that the dependency properties 'PropertyChanged' methods are exactly the same, it seems like a lot of redundant code.

SourceB_PropertyChanged...
SourceA_PropertyChanged...

I don't feel like I'm doing this properly. Is there a way for me to remove the redundancy while maintaining the Notification for collection changed?

The Code

using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace NexusEditor
{
    /// <summary>
    /// The main class that implements the network/flow-chart control.
    /// </summary>
    public partial class NexusEditor : Control
    {
        #region Dependency Property/Event Definitions

        private static readonly DependencyPropertyKey ItemsPropertyKey =
            DependencyProperty.RegisterReadOnly("Items", typeof(ObservableCollection<object>), typeof(NexusEditor),
                new FrameworkPropertyMetadata());
        public static readonly DependencyProperty ItemsProperty = ItemsPropertyKey.DependencyProperty;

        public static readonly DependencyProperty SourceAProperty =
            DependencyProperty.Register("SourceA", typeof(IEnumerable), typeof(NexusEditor),
                new FrameworkPropertyMetadata(SourceA_PropertyChanged));

        public static readonly DependencyProperty SourceBProperty =
            DependencyProperty.Register("SourceB", typeof(IEnumerable), typeof(NexusEditor),
                new FrameworkPropertyMetadata(SourceB_PropertyChanged));

        #endregion


        #region Constructors

        public NexusEditor()
        {
            // Create a collection to contain nodes.
            this.Items = new ObservableCollection<object>();
        }

        static NexusEditor()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NexusEditor), new FrameworkPropertyMetadata(typeof(NexusEditor)));
        }

        #endregion

        #region properties

        public IEnumerable SourceA
        {
            get { return (IEnumerable)GetValue(SourceAProperty); }
            set { SetValue(SourceAProperty, value); }
        }

        public IEnumerable SourceB
        {
            get { return (IEnumerable)GetValue(SourceBProperty); }
            set { SetValue(SourceBProperty, value); }
        }

        /// <summary>
        /// Collection of items
        /// </summary>
        public ObservableCollection<object> Items
        {
            get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
            private set { SetValue(ItemsPropertyKey, value); }
        }

        #endregion

        #region privates

        private static void UpdateItems(NexusEditor editor)
        {
            editor.Items.Clear();

            var sourceB = editor.SourceB as IEnumerable;
            if (sourceB != null)
            {
                foreach (object obj in sourceB)
                {
                    editor.Items.Add(obj);
                }
            }

            var sourceA = editor.SourceA as IEnumerable;
            if (sourceA != null)
            {
                foreach (object obj in sourceA)
                {
                    editor.Items.Add(obj);
                }
            }
        }

        /// <summary>
        /// Event raised when a new collection has been assigned to the SourceB property.
        /// </summary>
        private static void SourceB_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NexusEditor c = (NexusEditor)d;

            if (e.OldValue != null)
            {
                var notifyCollectionChanged = e.OldValue as INotifyCollectionChanged;
                if (notifyCollectionChanged != null)
                {
                    notifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(c.SourceB_CollectionChanged);
                }
            }

            if (e.NewValue != null)
            {
                var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
                if (notifyCollectionChanged != null)
                {
                    notifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(c.SourceB_CollectionChanged);
                }
            }

            UpdateItems(c);
        }

        /// <summary>
        /// Event raised when a node has been added to or removed from the collection assigned to 'NodesSource'.
        /// </summary>
        private void SourceB_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            UpdateItems(this);
        }


        /// <summary>
        /// Event raised when a new collection has been assigned to the SourceB property.
        /// </summary>
        private static void SourceA_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            NexusEditor c = (NexusEditor)d;

            if (e.OldValue != null)
            {
                var notifyCollectionChanged = e.OldValue as INotifyCollectionChanged;
                if (notifyCollectionChanged != null)
                {
                    notifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(c.SourceA_CollectionChanged);
                }
            }

            if (e.NewValue != null)
            {
                var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
                if (notifyCollectionChanged != null)
                {
                    notifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(c.SourceA_CollectionChanged);
                }
            }

            UpdateItems(c);
        }

        /// <summary>
        /// Event raised when a node has been added to or removed from the collection assigned to 'NodesSource'.
        /// </summary>
        private void SourceA_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            UpdateItems(this);
        }

        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

        }
    }
}

Upvotes: 0

Views: 163

Answers (1)

Szabolcs D&#233;zsi
Szabolcs D&#233;zsi

Reputation: 8843

Why don't you create one PropertyChanged handler method named Source_PropertyChanged for example and use that for both dependency properties?

If they're exactly the same you can just do that.

public static readonly DependencyProperty SourceAProperty =
    DependencyProperty.Register("SourceA", typeof(IEnumerable), typeof(NexusEditor), 
    new FrameworkPropertyMetadata(Source_PropertyChanged));

public static readonly DependencyProperty SourceBProperty =
    DependencyProperty.Register("SourceB", typeof(IEnumerable), typeof(NexusEditor),
    new FrameworkPropertyMetadata(Source_PropertyChanged));

The handler:

private static void Source_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    NexusEditor c = (NexusEditor)d;

    if (e.OldValue != null)
    {
        var notifyCollectionChanged = e.OldValue as INotifyCollectionChanged;
        if (notifyCollectionChanged != null)
        {
            notifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(c.Source_CollectionChanged);
        }
    }

    if (e.NewValue != null)
    {
        var notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
        if (notifyCollectionChanged != null)
        {
            notifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(c.Source_CollectionChanged);
        }
    }

    UpdateItems(c);
}

For the collection changed:

private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    UpdateItems(this);
}

Upvotes: 1

Related Questions