CommandBinding and ComboBox ViewModel Issue

Topics: Prism v2 - WPF 3.5
Dec 18, 2009 at 12:44 PM

Hi,

  As you may be aware there is issue with using ComboBoxes with MVVM design pattern (see: http://social.msdn.microsoft.com/forums/en-US/wpf/thread/30a45233-dc01-40ca-9ead-fa816c395697/)

So I found an example of how to solve this issue, but I am not sure how to implement this in Prism using DelegateCommand. I have the following ViewModel (which works as intended)

 

public class ProductCategoriesViewModel : DependencyObject
	{
		#region Fields

		private PopUpCollection<ProductCategory> categoryList =
			new PopUpCollection<ProductCategory>();
		#endregion
        ICommand ItemSelectedCommand { get; set; }

        public void SelectCategory(object parameter)
        {
            ViewModel.ProductCategory selectedCategory = parameter as ViewModel.ProductCategory;
            MessageBox.Show("Selected Category: " + selectedCategory.Name);
        }
		public ProductCategoriesViewModel()
		{
     //       ItemSelectedCommand = new DelegateCommand<int>(this.SelectCategory);
            SetValue(ShowMessageCommandProperty, new ShowMessageBoxCommand(this));
            SetValue(ItemCommandProperty, new ItemSelectedCommand(this));
           // SetValue(ItemCommandProperty, ItemSelectedCommand);
            AdvWorksDataContext db = new AdvWorksDataContext();
            var res = (from pc in db.ProductCategories
                      select new ProductCategory
                      {
                          Name = pc.Name,
                          ModifiedDate = pc.ModifiedDate,
                      }).ToList<ProductCategory>();

         

			//Load popup friendly list.
            foreach (var pc in res)
                categoryList.Add(pc);

 
			categoryList[2].IsSelected = true;//select a category
		}

		

		public Additional.PopUpCollection<ProductCategory> CategoryList
		{
			get { return categoryList; }
		}

        

        public static readonly DependencyProperty ItemCommandProperty =
            DependencyProperty.Register("ItemCommand", typeof(ItemSelectedCommand), typeof(ProductCategoriesViewModel));

        /// <summary>
        /// 
        /// </summary>
        //public ItemSelectedCommand ItemCommand
        //{
        //    get
        //    {
        //        return GetValue(ItemCommandProperty) as ItemSelectedCommand;
        //    }
        //    set
        //    {
        //        SetValue(ItemCommandProperty, value);
        //    }
        //}
        public static readonly DependencyProperty ShowMessageCommandProperty =
            DependencyProperty.Register("ShowMessageCommand", typeof(ShowMessageBoxCommand), typeof(ProductCategoriesViewModel));

        /// <summary>
        /// 
        /// </summary>
        public ShowMessageBoxCommand ShowMessageCommand
        {
            get
            {
                return GetValue(ShowMessageCommandProperty) as ShowMessageBoxCommand;
            }
            set
            {
                SetValue(ShowMessageCommandProperty, value);
            }
        }
}

 

 

My view is declared as follows:

 

<Window x:Class="derek.kowald.PopUpSelector.CategorizedProductCollectionView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:derek.kowald.PopUpSelector"
		xmlns:vm="clr-namespace:derek.kowald.PopUpSelector.ViewModel"
    Title="PopUp Selection Demo"
		Width="300" Height="130">
	<Window.Resources>
		<ObjectDataProvider x:Key="Data" ObjectType="{x:Type vm:ProductCategoriesViewModel}" />
		
		<Style TargetType="{x:Type StackPanel}">
			<Setter Property="Margin" Value="3" />
		</Style>
		
		<Style TargetType="{x:Type ComboBoxItem}">
			<!-- Sync the lists selected item with the ViewModel IsSelected-->
			<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
		</Style>
		
		<DataTemplate DataType="{x:Type vm:ProductCategory}">
			<TextBlock Text="{Binding Path=Name}" />
		</DataTemplate>
	</Window.Resources>
	
	<StackPanel Orientation="Vertical" DataContext="{StaticResource Data}">
		<StackPanel Orientation="Horizontal"></StackPanel>
		
		<StackPanel Orientation="Horizontal">
			<TextBlock Text="Popup Collection" />
			<ComboBox ItemsSource="{Binding Path=CategoryList}"
								IsSynchronizedWithCurrentItem="True"
                                local:ItemSelectedBehavior.ItemSelected="{Binding Path = ItemCommand}"
								SelectedValue="{Binding Path=CategoryList.SelectedValue, Mode=TwoWay}"/>
		</StackPanel>
		
	</StackPanel>
</Window>

The ItemSelectedBehavior is declared as follows:
public static class ItemSelectedBehavior
    {
        public static DependencyProperty ItemSelectedProperty =
            DependencyProperty.RegisterAttached("ItemSelected",
                typeof(ICommand),
                typeof(ItemSelectedBehavior),
                new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ItemSelectedBehavior.ItemSelectedChanged)));

        public static void SetItemSelected(DependencyObject target, ICommand value)
        {
            target.SetValue(ItemSelectedBehavior.ItemSelectedProperty, value);
        }

        private static void ItemSelectedChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            Selector element = target as Selector;

            if (element != null)
            {
                // If we're putting in a new command and there wasn't one already
                // hook the event
                if ((e.NewValue != null) && (e.OldValue == null))
                {
                    element.SelectionChanged += element_SelectionChanged;
                }
                // If we're clearing the command and it wasn't already null
                // unhook the event
                else if ((e.NewValue == null) && (e.OldValue != null))
                {
                    element.SelectionChanged -= element_SelectionChanged;
                }
            }
        }

        private static void element_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            Selector element = sender as Selector;
            if (element != null)
            {
                ICommand command = (ICommand)element.GetValue(ItemSelectedBehavior.ItemSelectedProperty);
                command.Execute(element.SelectedItem);
            }
        }
    }
The ItemSelectedCommand is as follows;
public class ItemSelectedCommand : ICommand
        {
            private ProductCategoriesViewModel _ViewModel;
      
            public ItemSelectedCommand(ProductCategoriesViewModel view_model)
            {
                _ViewModel = view_model;
            }
            #region ICommand Members

            public bool CanExecute(object parameter)
            {
                return true;
            }

       
            public event EventHandler CanExecuteChanged;

          
            public void Execute(object parameter)
            {
               
                _ViewModel.SelectCategory(parameter);
               // MessageBox.Show("selected category:" + slected.Name);
            }

            #endregion
        }
I have uploaded the sample project at http://cid-9e01849c63c42126.skydrive.live.com/browse.aspx/AdvWorksPrism?uc=1

If anyone guide me how to change the above implementation using DelegateCommand, it would really help.

regards
Arun
		
		
		
			<Setter Property="Margin" Value="3" />
		
		
		
			<!-- Sync the lists selected item with the ViewModel IsSelected-->
			<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
		
		
		
			
		
	
	
	
		
		
		
			
			
		
		
	

 

 

public class ProductCategoriesViewModel : DependencyObject
{
#region Fields
private Additional.PopUpCollection<ProductCategory> categoryList =
new Additional.PopUpCollection<ProductCategory>();
#endregion
        ICommand ItemSelectedCommand { get; set; }
        public void SelectCategory(object parameter)
        {
            ViewModel.ProductCategory selectedCategory = parameter as ViewModel.ProductCategory;
            MessageBox.Show("Selected Category: " + selectedCategory.Name);
        }
public ProductCategoriesViewModel()
{
     //       ItemSelectedCommand = new DelegateCommand<int>(this.SelectCategory);
            SetValue(ShowMessageCommandProperty, new ShowMessageBoxCommand(this));
            SetValue(ItemCommandProperty, new ItemSelectedCommand(this));
           // SetValue(ItemCommandProperty, ItemSelectedCommand);
            AdvWorksDataContext db = new AdvWorksDataContext();
            var res = (from pc in db.ProductCategories
                      select new ProductCategory
                      {
                          Name = pc.Name,
                          ModifiedDate = pc.ModifiedDate,
                      }).ToList<ProductCategory>();
         
//Load popup friendly list.
            foreach (var pc in res)
                categoryList.Add(pc);
 
categoryList[2].IsSelected = true;//select a category
}
public Additional.PopUpCollection<ProductCategory> CategoryList
{
get { return categoryList; }
}
        
        public static readonly DependencyProperty ItemCommandProperty =
            DependencyProperty.Register("ItemCommand", typeof(ItemSelectedCommand), typeof(ProductCategoriesViewModel));
        /// <summary>
        /// 
        /// </summary>
        //public ItemSelectedCommand ItemCommand
        //{
        //    get
        //    {
        //        return GetValue(ItemCommandProperty) as ItemSelectedCommand;
        //    }
        //    set
        //    {
        //        SetValue(ItemCommandProperty, value);
        //    }
        //}
        public static readonly DependencyProperty ShowMessageCommandProperty =
            DependencyProperty.Register("ShowMessageCommand", typeof(ShowMessageBoxCommand), typeof(ProductCategoriesViewModel));
        /// <summary>
        /// 
        /// </summary>
        public ShowMessageBoxCommand ShowMessageCommand
        {
            get
            {
                return GetValue(ShowMessageCommandProperty) as ShowMessageBoxCommand;
            }
            set
            {
                SetValue(ShowMessageCommandProperty, value);
            }
        }
}