C#WPF ComboBox自动切换号码

时间:2013-04-07 06:32:00

标签: c# wpf controls

如何以简单的方式管理ComboBox中的自动切换号码?

Problem example

3 个答案:

答案 0 :(得分:1)

你不应该这样做。您应该呈现用户可以拖放的用户可交换用户控件,使用鼠标更改顺序。

你的解决方案并不是那么好,但是如果你仍然想要这样做,那么在combobox selectitem事件中查看具有该值的其他组合框并将其更改为前一个。

答案 1 :(得分:0)

只需在数据模型中切换值即可。因此,当数据模型的属性发生变化时,将更新wpf控件。

XAML:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:model="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <model:DataModel x:Key="MyModel" />
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <ItemsControl Grid.Column="0" Grid.Row="0" DataContext="{StaticResource MyModel}"
                      ItemsSource="{Binding Items}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding Items}">
                    </ComboBox>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

代码:

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;

namespace WpfApplication2
{
    public class DataModel
    {
        #region Construction and Initialization

        public DataModel()
        {
            var elements = new[] {1, 2, 3, 4, 5};
            Items = new List<ItemsModel>
                {
                    new ItemsModel(elements, 1),
                    new ItemsModel(elements, 2),
                    new ItemsModel(elements, 3),
                    new ItemsModel(elements, 4),
                    new ItemsModel(elements, 5)
                };

            foreach (var itemsModel in Items)
            {
                itemsModel.PropertyChanged += SelectedItemChanged;
            }
        }

        #endregion

        public List<ItemsModel> Items { get; private set; }

        private void SelectedItemChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "SelectedItem")
            {
                var model = sender as ItemsModel;
                Debug.Assert(model != null, "model != null");
                int pos = Items.IndexOf(model) + 1;
                Items[model.SelectedItem - 1].SelectedItem = pos;
            }
        }
    }

    public class ItemsModel: INotifyPropertyChanged
    {
        #region Construction and Initialization

        public ItemsModel(IEnumerable<int> items, int selectedItem)
        {
            Items = items;
            _selectedItem = selectedItem;
        }

        #endregion

        public int SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (_selectedItem != value)
                {
                    _selectedItem = value;
                    RaisePropertyChanged("SelectedItem");
                }
            }
        }

        private int _selectedItem;

        public IEnumerable<int> Items { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

答案 2 :(得分:0)

您可以在ViewModel中添加单独的属性,并在视图中单独的ComboBox,然后在ViewModel中值更改时操作值,但这很麻烦,并且在添加新的ComboBox(值)时需要做很多工作

更好的方法是创建一个处理更改的自定义集合:

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;
            }
        }
    }
}

然后像这样定义你的ViewModel:

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; }
    }
}

并在您的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>

这是很多代码!但是这个任务很好,而且非常易于维护。