2013-04-07 5 views

Répondre

0

Vous pouvez ajouter des propriétés séparées dans votre ViewModel et séparer les zones de liste déroulantes dans la vue, puis manipuler les valeurs lorsqu'une valeur change dans ViewModel, mais cela est fastidieux et implique beaucoup de travail lorsque vous ajoutez une nouvelle zone de liste.).

Une meilleure approche est de créer une collection personnalisée qui gère les changements:

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

Réglez ensuite votre ViewModel comme ceci:

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

et dans votre 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> 

Ceci est beaucoup de code! Mais fait la tâche bien, et est également très maintenable.

+0

bien! mais qu'en est-il dans un ComboBox multiple ou séparé dans xaml? – Jesson

+0

ce code fonctionne super .. mais pas son pas sur mon xaml j'ai 5 combobox séparé je veux obtenir chaque valeur et l'enregistrer sur ma base de données .. y at-il une autre approche pour ComboBox séparé? – Jesson

0

zappent valeurs dans votre modèle de données. Par conséquent, les contrôles wpf seront mis à jour lorsque les propriétés du modèle de données seront modifiées.

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> 

code:

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)); 
      } 
     } 
    } 
} 
+0

pouvez-vous montrer un exemple de code? – Jesson

+0

Ajout de l'exemple de code. – Alexey

1

Vous ne devriez pas le faire de cette façon. Vous devez présenter les commandes utilisateur permutables que l'utilisateur peut faire glisser et déposer, en changeant l'ordre avec la souris.

Votre solution n'est pas très bonne, mais si vous voulez toujours faire cela, dans l'événement selectitem de la liste déroulante, regardez les autres combobox avec cette valeur et remplacez-la par la précédente.