Archive for the ‘ MVVM – Environment ’ Category

WPF – Custom IsSynchronizedWithCurrentItem implementation

Hi guys,

if you ever missed the IsSynchronizedWithCurrentItem property in one of your controls you might need this.
Well basically you can enable a feature using this property which is synchronizing the selected item of your Control (ListBox, ComboBox, etc.) with the current item of the collection to which you bind to.

In my case I needed this feature in the Telerik RadListBox. Therefore I created an attached property which simulates this feature.
Basically what I’m doing is the following:

  • When the SelectedItem in the ListBox was changed => update the CurrentItem in the Collection
  • When the CurrentItem in the Collection was changed => update the SelectedItem of the ListBox

The tricky part here is that the user might bind a new collection to the control. Such that you have to notice that the collection was changed and register the events for the new collection.
Therefore I used this ListBoxSources-Dictionary which contains the key value pairs of the listboxes and their corresponding collections.
If the collection is different from the one it has before we know that it was changed and have to unregister the events in the old collection and register then in the new collection.

Here is the code I was talking about:

 /// <summary>
  ///   This class contains a few useful extenders for the ListBox.
  /// </summary>
  public class RadListBoxExtensions : DependencyObject
  {
    private static readonly Dictionary<RadListBox, object> ListBoxSources = new Dictionary<RadListBox, object>();

    public static readonly DependencyProperty IsSynchronizedWithCurrentItemProperty = DependencyProperty.RegisterAttached("IsSynchronizedWithCurrentItem", typeof (bool), typeof (RadListBoxExtensions), new UIPropertyMetadata(default(bool), OnIsSynchronizedWithCurrentItemChanged));

    /// <summary>
    ///   Returns the value of the IsSynchronizedWithCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be returned</param>
    /// <returns>The value of the given property</returns>
    public static bool GetIsSynchronizedWithCurrentItem(DependencyObject obj)
    {
      return (bool) obj.GetValue(IsSynchronizedWithCurrentItemProperty);
    }

    /// <summary>
    ///   Sets the value of the IsSynchronizedWithCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be set</param>
    /// <param name="value">The value which should be assigned to the AutoScrollToCurrentItemProperty</param>
    public static void SetIsSynchronizedWithCurrentItem(DependencyObject obj, bool value)
    {
      obj.SetValue(IsSynchronizedWithCurrentItemProperty, value);
    }

    /// <summary>
    ///   This method will be called when the IsSynchronizedWithCurrentItem property was changed
    /// </summary>
    /// <param name="s">The sender (the RadListBox)</param>
    /// <param name="e">Some additional information</param>
    public static void OnIsSynchronizedWithCurrentItemChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
      var listBox = s as RadListBox;
      if (listBox != null)
      {
        var newValue = (bool) e.NewValue;
        var selectionChangedWorker = new SelectionChangedEventHandler((s1, e2) => OnSelectionChanged(listBox, listBox.SelectedItem));
        if (newValue)
        {
          listBox.Loaded += OnLoaded;
          listBox.SelectionChanged += selectionChangedWorker;
        }
        else
        {
          listBox.Loaded -= OnLoaded;
          listBox.SelectionChanged -= selectionChangedWorker;
        }
      }
    }

    /// <summary>
    ///   Called when when the listbox was loaded.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">
    ///   The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.
    /// </param>
    private static void OnLoaded(object sender, RoutedEventArgs e)
    {
      var listBox = sender as RadListBox;
      if (listBox == null)
        return;
      var collection = listBox.ItemsSource;
      ActivateCollectionIfNecessary(listBox, collection);
    }

    /// <summary>
    ///   Called when the selection was changed.
    /// </summary>
    /// <param name="listBox">The list box.</param>
    /// <param name="selectedItem">The selected item.</param>
    private static void OnSelectionChanged(RadListBox listBox, object selectedItem)
    {
      var collection = listBox.ItemsSource;
      ActivateCollectionIfNecessary(listBox, collection);
      var defaultView = CollectionViewSource.GetDefaultView(collection);
      if (defaultView != null)
        defaultView.MoveCurrentTo(selectedItem);
    }

    /// <summary>
    ///   Activates the collection if necessary.
    /// </summary>
    /// <param name="listBox">The listbox.</param>
    /// <param name="collection">The collection.</param>
    private static void ActivateCollectionIfNecessary(RadListBox listBox, object collection)
    {
      if (!ListBoxSources.ContainsKey(listBox))
        ListBoxSources.Add(listBox, collection);
      else if (ListBoxSources[listBox] == collection)
        return;
      var oldCollection = ListBoxSources[listBox];
      var newView = CollectionViewSource.GetDefaultView(collection);
      var currentChangedWorker = new EventHandler((s1, e2) => listBox.SelectedItem = newView.CurrentItem);

      if (oldCollection != null)
      {
        var oldView = CollectionViewSource.GetDefaultView(oldCollection);
        if (oldView != null)
          oldView.CurrentChanged -= currentChangedWorker;
      }
      ListBoxSources[listBox] = collection;

      if (newView != null)
      {
        newView.CurrentChanged += currentChangedWorker;
        listBox.SelectedItem = newView.CurrentItem;
      }
    }
}

Have fun!

Advertisements

MVVM – Environment – MGDispatchingWorker

In the MVVM pattern I always need the same base structure of the DispatchingWorker.
This class is located between the ViewModel and the Worker. It is responsible for running the actions in the right thread.

And this class has always the same base structure. So I decided to create my own base class which I can easily extend.

Well here is the result. It just contains a few necessary methods to run actions in the GUI-Thread or in a new Worker Thread.

    /// <summary>
    /// This class can be used as a base for the DispatchingWorker of the MVVM Pattern
    /// It contains a few util methods which help to run methods in Threads or to do Actions in the GUI-Thread
    /// </summary>
    public class MGDispatchingWorker
    {
        public DispatchingWorker()
        {
            _currentDispatcher = Dispatcher.CurrentDispatcher;
        }

        #region Field

        private readonly Dispatcher _currentDispatcher;

        #endregion

        #region UtilMethods

        /// <summary>
        /// This method runs the given action in a new thread (not GUI-Thread)
        /// </summary>
        /// <param name="action">The action which should be run in a new Thread</param>
        protected void DoThreadedAction(Action action)
        {
            var thread = new Thread(action.Invoke);
            thread.Start();
        }

        /// <summary>
        /// This method executes the given action in the GUI-Thread
        /// </summary>
        /// <param name="action">The action which should be executed in the GUI-Thread</param>
        protected void DoDispatchedAction(Action action)
        {
            if (_currentDispatcher.CheckAccess())
                action.Invoke();
            else
                _currentDispatcher.Invoke(action);
        }

        /// <summary>
        /// This method executed the given action asynchronous in the GUI-Thread
        /// </summary>
        /// <param name="action">The action which should be executed asynchronous in the GUI-Thread</param>
        protected void DoDispatchedActionAsync(Action action)
        {
            if (_currentDispatcher.CheckAccess())
                action.Invoke();
            else
                _currentDispatcher.BeginInvoke(action);
        }

        #endregion
    }

MVVM – Environment – MGViewModel

In the MVVM pattern I always need the same base structure of the ViewModel.

So I decided to write my own class which could be extended when creating a new ViewModel.
Such that I do not have to implement the same features each time.

This base class implements INotifyPropertyChanged and a few methods which makes it easy to fire this eventt when one of the properties changed.

The NotifyPropertyChanged-Method which takes the propertyExpression parameter is by Eric De Caroufel

public  class MGViewModel : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Member

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Util Methods

        /// <summary>
        /// This method fires the PropertyChanged-Event
        /// </summary>
        /// <param name="propertyExpression">The expression which contains the variable which was changed</param>
        protected void NotifyPropertyChanged(Expression<Func<object>> propertyExpression)
        {
            var propertyChanged = PropertyChanged;
            if (propertyChanged != null)
            {
                // Retreive lambda body
                var body = propertyExpression.Body as MemberExpression;
                if (body == null)
                    throw new ArgumentException("'propertyExpression' should be a member expression");

                // Extract the right part (after "=>")
                var vmExpression = body.Expression as ConstantExpression;
                if (vmExpression == null)
                    throw new ArgumentException("'propertyExpression' body should be a constant expression");

                // Create a reference to the calling object to pass it as the sender
                LambdaExpression vmlambda = Expression.Lambda(vmExpression);
                Delegate vmFunc = vmlambda.Compile();
                object vm = vmFunc.DynamicInvoke();

                // Extract the name of the property to raise a change on
                string propertyName = body.Member.Name;
                var e = new PropertyChangedEventArgs(propertyName);
                propertyChanged(vm, e);
            }
        }

        /// <summary>
        /// This method fires the PropertyChanged-Event
        /// </summary>
        /// <param name="name">The name of the variable which was changed</param>
        protected void NotifyPropertyChanged(string name)
        {
            if(PropertyChanged!=null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
        
        #endregion
    }