0

I have a combobox binded to a Observeable Collection. The Collection is a container for a selfdefined class.

I need to delete an arbitary item from the combobox by pressing the right mouse button when hovering my mouse cursor over the item of the dropdown list. I also need to delete it by pressing the delete button when the item is highlighted.

I already have a solution in the code behind, but i need to do it with the MVVM-Pattern.

Can anyone help me in this issue pls?

Thx in advance :).

Here are my codes:

My ViewModel:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Catel.MVVM;
using System.Windows.Input;
using DeleteItemFromComboBox.Models;
using Catel.Data;

namespace DeleteItemFromComboBox.ViewModels
{
    public class MainWindowVM : ViewModelBase
    {

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindowVM"/> class.
        /// </summary>
        public MainWindowVM()
        {
            PreviewKeyDownCmd = new Command<KeyEventArgs>(PreviewKeyDownCmdExecute);
            PersonList = new ObservableCollection<Person>();
            PersonList.Add(new Person("AA"));
            PersonList.Add(new Person("BB"));
        }
        #endregion


        #region Properties
        /// <summary>
        /// Gets or sets the property value.
        /// </summary>
        public ObservableCollection<Person> PersonList
        {
            get { return GetValue<ObservableCollection<Person>>(PersonListProperty); }
            set { SetValue(PersonListProperty, value); }
        }

        /// <summary>
        /// Register the PersonList property so it is known in the class.
        /// </summary>
        public static readonly PropertyData PersonListProperty = 
            RegisterProperty("PersonList", typeof(ObservableCollection<Person>), null);
        #endregion


        #region Commands
        /// <summary>
        /// Gets the PreviewKeyDownCmd command.
        /// </summary>
        public Command<KeyEventArgs> PreviewKeyDownCmd { get; private set; }

        /// <summary>
        /// Method to invoke when the PreviewKeyDownCmd command is executed.
        /// </summary>
        private void PreviewKeyDownCmdExecute(KeyEventArgs e)
        {
            if (e.Key == Key.Delete)
            {
                //********************What Should i do here?***************************
            }
        }
        #endregion
    }
}

XAML File:

<Window x:Class="DeleteItemFromComboBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ViewModels="clr-namespace:DeleteItemFromComboBox.ViewModels"
    Title="MainWindow" Height="350" Width="525"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:catel="http://catel.codeplex.com">

<Window.Resources>
    <ViewModels:MainWindowVM x:Key="ViewModel"/>
</Window.Resources>

<Grid DataContext="{Binding Source={StaticResource ViewModel}}">
    <ComboBox Height="44" 
              HorizontalAlignment="Left" 
              Margin="12,12,0,0" 
              Name="comboBox1" 
              VerticalAlignment="Top" 
              Width="479"
              ItemsSource="{Binding PersonList, Mode=TwoWay}" >

        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewKeyDown">
                <catel:EventToCommand Command="{Binding PreviewKeyDownCmd}" DisableAssociatedObjectOnCannotExecute="False" />
            </i:EventTrigger>
        </i:Interaction.Triggers>

    </ComboBox>
</Grid>

Person Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Catel.MVVM;
using Catel.Data;
using System.Runtime.Serialization;

namespace DeleteItemFromComboBox.Models
{

#if !SILVERLIGHT
    [Serializable]
#endif
    public class Person : ModelBase
    {

        #region Constructors

        public Person() { }

        public Person(string name)
        {
            this.Name = name;
        }

#if !SILVERLIGHT
        protected Person(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
#endif
        #endregion

        /// <summary>
        /// Gets or sets the property value.
        /// </summary>
        [Model]
        public string Name
        {
            get { return GetValue<string>(NameProperty); }
            private set { SetValue(NameProperty, value); }
        }

        /// <summary>
        /// Register the Name property so it is known in the class.
        /// </summary>
        public static readonly PropertyData NameProperty = 
            RegisterProperty("Name", typeof(string));

        public override string ToString()
        {
            return Name;
        }
    }
}

Solution in Codebehind in a non MVVM-Project:

private void comboBox1_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Delete)
        {
            foreach (People item in comboBox1.Items)
            {
                ComboBoxItem cbi = this.comboBox1.ItemContainerGenerator.ContainerFromItem(item) as ComboBoxItem;

                if (cbi.IsHighlighted == true)
                {
                    peoples.Remove(item);
                    return;
                }
            }
        }
    }
Benjamin Martin
  • 576
  • 1
  • 8
  • 27
  • I don't think the cast is needed in this `((ComboBoxItem)cbi).IsHighlighted`, just `cbi.IsHighlighted` is OK. – King King Jul 11 '13 at 17:35

2 Answers2

0

The easiest way is to create a property SelectedPerson. As soon as the user right-clicks on an item, it will automatically set the SelectedPerson. Then you can also create a toolbar which uses the same command as the popup to delete the selected item in a list.

When you use the SelectedPerson method, you can use code like this:

MyCollection.Remove(SelectedPerson);
SelectedPerson = null;

Make sure that in your OnCanExecute, you check whether SelectedPerson != null.

Geert van Horrik
  • 5,689
  • 1
  • 18
  • 32
  • Hi Geert, thank you for your fast answer. This might be a very good alternative solution but unfortunately i need to implement the asked feature above because the selectedperson is binded to the selectedchanged event and the system updates the selectedperson only when the selected item is changed. When the item selected item is changed my programm then needs to handle an other task. Btw your CATEL framework is very matured and the support is great :). I love it. Keep up the good work :). – Benjamin Martin Jul 16 '13 at 06:55
0

I used one of these approaches to solve the problem:

  1. Cast the MouseButtonEventArgs e.Source to Combobox and then apply the solution i mentioned above to do the task. Just remove IPlan with a type of your choice.

    private void Plan_PreviewMouseRightButtonDownCmd_Execute(MouseButtonEventArgs e)
    {
        ComboBox comboBox =  e.Source as ComboBox;
        if(comboBox!=null)
        {
            foreach (IPlan item in comboBox.Items)
            {
                ComboBoxItem cbi = comboBox.ItemContainerGenerator.ContainerFromItem(item) as ComboBoxItem;
    
                if (cbi.IsHighlighted == true)
                    SelectedPlans.Remove(item);
    
                if (item == SelectedPlan)
                    SelectedPlan = null;
            }
        }
    }
    
  2. Use this custom implementation of combobox and bind the itemindex to an property in code behind. Then you can delete the item via MyCollection.RemoveAt();

http://www.codeproject.com/Articles/14255/ComboBox-firing-events-when-hovering-on-the-dropdo

Benjamin Martin
  • 576
  • 1
  • 8
  • 27