6

Goal is to have multiple Combobox, once the item is selected in any of the Combobox, it should be removed or hided from other Comboboxes for selection.

I'm able to change the source whenever the selection got changed on any of the Comboboxes. But Problem is when I remove the selected item from the ItemsSource, item got removed from all the sources including the one on which I selected.

Here is the sample

xaml

<StackPanel>
    <ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
    <ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
    <ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
    <ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
</StackPanel>

Codebehind

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ObservableCollection<string> s = new ObservableCollection<string>();
        s.Add("item1");
        s.Add("item2");
        s.Add("item3");
        s.Add("item4");
        s.Add("item5");
        s.Add("item6");

        DataContext = new MainViewModel() { ComboboxItems = s , SelectedItem = "item2" };

    }
}

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<string> comboboxitems;

    public ObservableCollection<string> ComboboxItems
    {
        get { return comboboxitems; }  
        set { comboboxitems = value; OnPropertyChanged("ComboboxItem"); }
    }

    private string _selectedItem;

    public string SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            comboboxitems.Remove(value);  //here removing selected item from itemssource
            OnPropertyChanged("SelectedItem");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propname)
    {
        if(PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propname));
    }
}

I know I can have multiple Collection for each Combobox but that may take lot of memory if number of Combobox increases.

Hope, there should be a easy way to achieve this in WPF.

Gopichandar
  • 2,742
  • 2
  • 24
  • 54
  • 1
    Well in this case you would have to create multiple SelectedItem properties, one for each combobox I believe. eg SelectedItem1, SelectedItem2 and so on, but the ItemsSource can be shared. – adminSoftDK May 18 '16 at 10:44
  • Use CollectionView or CollectionViewSource- which is proxy for your actual source. This will allow to share common source via View property and you can have different selected items(CurrentItem) for each CollectionView. – dipak May 18 '16 at 10:48
  • @adminSoftDK Yes we can., but how can I remove or restrict the item from selection on other `Combobox`? – Gopichandar May 18 '16 at 11:03
  • Each combobox would need a style and triggers, to do this. So if the current item equals OtherSelectedItem then apply something to this item. I don't have the time to make a code sample right now. But hopefully you get the idea. – adminSoftDK May 18 '16 at 11:21

1 Answers1

4

You could define different SelectedItem for each ComboBox, and then create a wrapper of the SharedItemSource for each ComboBoxto filter out the SelectedItem of other ComboBox. eg:

C# :

    public IEnumerable<string> ComboboxItems1
    {
        get
        {
            return ComboboxItems.Where(x => x != SelectedItem2 && x != SelectedItem3);
        }
    }

    public string SelectedItem1
    {
        get { return _selectedItem1; }
        set
        {
            if (_selectedItem1 != value)
            {
                _selectedItem1 = value;
                RaisePropertyChanged("SelectedItem1");
                RaisePropertyChanged("ComboboxItems2"); //raise propertychanged to refresh GUI 
                RaisePropertyChanged("ComboboxItems3");
            }
        }
    }       

    public IEnumerable<string> ComboboxItems2
    {
        get
        {
            return ComboboxItems.Where(x => x!=SelectedItem1&&x!=SelectedItem3);
        }
    }

    public string SelectedItem2
    {
        get { return _selectedItem2; }
        set
        {
            if (_selectedItem2 != value)
            {
                _selectedItem2 = value;                   
                RaisePropertyChanged("SelectedItem2");
                RaisePropertyChanged("ComboboxItems1"); //raise propertychanged to refresh GUI
                RaisePropertyChanged("ComboboxItems3");
            }
        }
    }

    public IEnumerable<string> ComboboxItems3
    {
        get
        {
            return ComboboxItems.Where(x => x != SelectedItem1 && x != SelectedItem2);
        }
    }

    public string SelectedItem3
    {
        get { return _selectedItem3; }
        set
        {
            if (_selectedItem3 != value)
            {
                _selectedItem3 = value;                 
                RaisePropertyChanged("SelectedItem3");
                RaisePropertyChanged("ComboboxItems1"); //raise propertychanged to refresh GUI
                RaisePropertyChanged("ComboboxItems2");
            }
        }
    }

XAML:

<ComboBox SelectedItem="{Binding SelectedItem1}" ItemsSource="{Binding ComboboxItems1}" />
<ComboBox  SelectedItem="{Binding SelectedItem2}" ItemsSource="{Binding ComboboxItems2}" />
<ComboBox  SelectedItem="{Binding SelectedItem3}" ItemsSource="{Binding ComboboxItems3}" />
Bolu
  • 8,696
  • 4
  • 38
  • 70
  • . I leads to `Stack overflow` exception as the `ItemsSource` refresh the `SelectedItem1`. – Gopichandar May 19 '16 at 07:47
  • Can you set up a break point and try to get more information about the exception. – Bolu May 19 '16 at 08:23
  • Yes. On `OnPropertyChanged("ComboboxItems1");` it again triggers the `Set` of `SelectedItem1` which leads to deadlock. – Gopichandar May 19 '16 at 09:01
  • Could you post relevant code, it's not possible from the code I posted above. – Bolu May 19 '16 at 09:06
  • I think in your code, we are have a `ItemsSource` in a `Combobox`, on setting the `SelectedItem` in GUI triggers the `Set` of `SelectedItem` property on VM. Now, in `Set` we again changing the `ItemsSource` of the same `Combobox` where the previously `SelectedItem` is not there now as it is added to `C#Remove`. So it again triggers the `Set` of `SelectedItem` property and the loop goes on. . – Gopichandar May 19 '16 at 09:18
  • @Gopichandar, now I understand. So when you are removing the `selectedItem`, the `comboBox` still has to show an item as selected, which has caused the lock. Please see my updated answer, which added condition ` if(_selectedItem1 != value)` and will only trigger `propertychange` when selection has been changed. – Bolu May 19 '16 at 09:42
  • This is not going to give us solution as the selected item should be removed from other Comboboxes but not on the selected one. Also, if I change the selected item from a previously selected one, the previous one should be added for selection on others. Isn't it. . Hope I am clear – Gopichandar May 19 '16 at 09:42
  • I misunderstand your requirement a little bit, but it's easy to be fixed. I will update shortly. – Bolu May 19 '16 at 09:44
  • Updated one is _Perfect!_ Really thanks for you effort on this. – Gopichandar May 19 '16 at 10:14
  • @Gopichandar, glad it helped. – Bolu May 19 '16 at 10:20