[Solved] C# WPF ComboBox Auto switch number [closed]


You can add separate properties in your ViewModel and separate ComboBoxes in the view, then manipulate the values when a value changes in the ViewModel, but this is cumbersome, and involves a lot of work when you add a new ComboBox (value).

A better approach is to create a custom collection that handles the changes:

public class ValueHolder<T> : INotifyPropertyChanged
{
    private T _value;
    public T Value
    {
        get { return _value; }
        set
        {
            if (!EqualityComparer<T>.Default.Equals(value, _value))
            {
                T old = _value;
                _value = value;
                OnPropertyChanged("Value");
                OnValueChanged(old, value);
            }
        }
    }

    public ValueHolder()
    {
    }

    public ValueHolder(T value)
    {
        this._value = value;
    }

    public event EventHandler<ValueChangedEventArgs<T>> ValueChanged;
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnValueChanged(T oldValue, T newValue)
    {
        var h = ValueChanged;
        if (h != null)
            h(this, new ValueChangedEventArgs<T>(oldValue, newValue));
    }

    protected virtual void OnPropertyChanged(string propName)
    {
        var h = PropertyChanged;
        if (h != null)
            h(this, new PropertyChangedEventArgs(propName));
    }
}

public class ValueChangedEventArgs<T> : EventArgs
{
    public T OldValue { get; set; }
    public T NewValue { get; set; }

    public ValueChangedEventArgs(T oldValue, T newValue)
    {
        this.OldValue = oldValue;
        this.NewValue = newValue;
    }
}

public class MyCollection<T> : Collection<ValueHolder<T>>
{
    public void Add(T i)
    {
        this.Add(new ValueHolder<T>(i));
    }

    private void AddChangeHandler(ValueHolder<T> item)
    {
        item.ValueChanged += item_ValueChanged;
    }

    private void RemoveChangeHandler(ValueHolder<T> item)
    {
        item.ValueChanged -= item_ValueChanged;
    }

    protected override void InsertItem(int index, ValueHolder<T> item)
    {
        AddChangeHandler(item);
        base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
        RemoveChangeHandler(this[index]);
        base.RemoveItem(index);
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
        {
            RemoveChangeHandler(item);
        }
        base.ClearItems();
    }

    protected override void SetItem(int index, ValueHolder<T> item)
    {
        RemoveChangeHandler(this[index]);
        AddChangeHandler(item);
        base.SetItem(index, item);
    }

    private void item_ValueChanged(object sender, ValueChangedEventArgs<T> e)
    {
        ValueHolder<T> v = (ValueHolder<T>)sender;
        for (int i = 0; i < this.Count; i++)
        {
            if (this[i] == v)
                continue;
            if (EqualityComparer<T>.Default.Equals(this[i].Value, e.NewValue))
            {
                this[i].Value = e.OldValue;
                break;
            }
        }
    }
}

Then define your ViewModel like this:

public class MyViewModel
{
    private MyCollection<int> _values;

    public MyViewModel()
    {
        _values = new MyCollection<int>() { 1, 2, 3, 4, 5 };
    }

    public MyCollection<int> Values
    {
        get { return _values; }
    }
}

and in your xaml:

<ItemsControl ItemsSource="{Binding Path=Values}" Margin="10">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ComboBox SelectedValue="{Binding Path=Value}" Margin="5">
                <ComboBox.ItemsSource>
                    <Int32Collection >1,2,3,4,5</Int32Collection>
                </ComboBox.ItemsSource>
            </ComboBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

This is a lot of code! But does the task nicely, and also is very maintainable.

2

solved C# WPF ComboBox Auto switch number [closed]