2013-10-27 3 views
9

Я новичок в C# и MVVM, и я весь день пытался получить значение ComboBox в моей ViewModel на SelectionChanged. Мне удалось выяснить это с помощью либо CallMethodAction или InvokeCommandAction с ресурсами:WPF - MVVM: ComboBox значение после SelectionChanged

  • System.Windows.Interactivity.dll
  • Microsoft.Expression.Interactions.dll

Моя проблема заключается в том, что оба эти методы возвращают значение ComboBox, прежде чем он изменился , Может ли кто-нибудь объяснить, как получить значение после изменение?

Я потратил часы на поиск через SO и Google для решения, поэтому мне интересно, другие ли тоже. Любые советы будут оценены!

Мой код ниже:

MainWindow.xaml

<Window x:Class="SelectionChange.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
     xmlns:si="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions" 
     xmlns:vm="clr-namespace:SelectionChange" 
     Title="MainWindow" Width="300" Height="300"> 
    <Window.DataContext> 
     <vm:ViewModel /> 
    </Window.DataContext> 
    <Grid> 
     <ComboBox Name="SelectBox" VerticalAlignment="Top" SelectedIndex="0"> 
      <i:Interaction.Triggers> 
       <i:EventTrigger EventName="SelectionChanged"> 
        <si:CallMethodAction MethodName="SelectionChanged" TargetObject="{Binding}" /> 
        <!--<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" CommandParameter="{Binding ElementName=SelectBox, Path=Text}" />--> 
       </i:EventTrigger> 
      </i:Interaction.Triggers> 
      <ComboBoxItem Content="Item 1" /> 
      <ComboBoxItem Content="Item 2" /> 
      <ComboBoxItem Content="Item 3" /> 
     </ComboBox> 
    </Grid> 
</Window> 

ViewModel.cs

namespace SelectionChange 
{ 
    using System; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Input; 

    public class ViewModel 
    { 
     public ViewModel() 
     { 
      SelectionChangedCommand = new SelectionChangedCommand(); 
     } 

     public ICommand SelectionChangedCommand 
     { 
      get; 
      set; 
     } 

     public void SelectionChanged(object sender, EventArgs e) 
     { 
      ComboBox SelectBox = (ComboBox)sender; 
      MessageBox.Show("Called SelectionChanged: " + SelectBox.Text); 
     } 
    } 
} 

SelectionChangedCommand.cs

namespace SelectionChange 
{ 
    using System; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Input; 

    public class SelectionChangedCommand : ICommand 
    { 
     public SelectionChangedCommand() 
     { 
     } 

     public event EventHandler CanExecuteChanged; 

     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 

     public void Execute(object parameter) 
     { 
      MessageBox.Show("Executed SelectionChangedCommand: " + parameter); 
     } 
    } 
} 




Edit: Мое решение

Оказывается, я не понял Binding достаточно хорошо, и вместо этого пытался сделать что-то простое в довольно сложно! Вместо использования зависимостей я теперь добился того, что мне нужно, используя регулярные привязки. В качестве примера я привязал TextBox к SelectedIndexComboBox, который обновляется с использованием INotifyPropertyChanged.

MainWindow.xaml Screenshot

MainWindow.xaml

<Window x:Class="SelectionChange.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:vm="clr-namespace:SelectionChange" 
     Title="MainWindow" Width="300" Height="300"> 
    <Window.DataContext> 
     <vm:ViewModel /> 
    </Window.DataContext> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto" /> 
      <ColumnDefinition Width="*" /> 
     </Grid.ColumnDefinitions> 

     <ComboBox SelectedItem="{Binding SelectedItem}" SelectedIndex="0" Grid.Column="0" VerticalAlignment="Top"> 
      <ComboBoxItem Content="Item 1" /> 
      <ComboBoxItem Content="Item 2" /> 
      <ComboBoxItem Content="Item 3" /> 
     </ComboBox> 

     <!-- TextBox to display the ComboBox's SelectedIndex --> 
     <TextBox Text="{Binding SelectedIndex}" Grid.Column="1" VerticalAlignment="Top" /> 
    </Grid> 
</Window> 

ViewModel.cs

namespace SelectionChange 
{ 
    using System; 
    using System.ComponentModel; 
    using System.Windows.Controls; 

    public class ViewModel : INotifyPropertyChanged 
    { 
     public ViewModel() 
     { 
     } 

     // Property to store/retrieve ComboBox's SelectedIndex 
     private int _SelectedIndex; 
     public int SelectedIndex { get; set; } 

     // Property to bind to ComboBox's SelectedItem 
     private ComboBoxItem _SelectedItem; 
     public ComboBoxItem SelectedItem 
     { 
      get { return _SelectedItem; } 
      set 
      { 
       _SelectedItem = value; 

       // SelectedItem's Content 
       string Content = (string)value.Content; 

       // SelectedItem's parent (i.e. the ComboBox) 
       ComboBox SelectBox = (ComboBox)value.Parent; 

       // ComboBox's SelectedIndex 
       int Index = SelectBox.SelectedIndex; 

       // Store the SelectedIndex in the property 
       SelectedIndex = Index; 

       // Raise PropertyChanged with the name of the stored property 
       RaisePropertyChanged("SelectedIndex"); 
      } 
     } 

     // INotifyPropertyChanged 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(string PropertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); 
     } 
    } 
} 
+0

Если я понимаю, что вы пытаетесь сделать, я думаю, что это поможет http://stackoverflow.com/questions/4765362/mvvm-combobox -binding – kenny

+0

Я просто отправлю идею для вас. Как насчет привязки свойства SelectedItems к свойству в ViewModel с режимом привязки TwoWay? Не нужно слушать событие SelectionChanged или создавать команды. Всякий раз, когда значение SelectedItems изменяется, вы получите уведомление внутри установщика вашего объекта в ViewModel. Попробуйте. –

+0

. Попробуйте что-то вроде этого. – srsyogesh

ответ

19

Почему бы не сделать это простой способ

<ComboBox MaxHeight="25" 
      ItemsSource="{Binding Source}" 
      SelectedItem="{Binding TheSelectedItem, Mode=TwoWay}" /> 

В вашей ViewModel декларировать элементы комбо коробки и использовать свойство «Source», чтобы вернуть его к виду

List<string> _source = new List<string>{"Item 1", "Item 2", "Item 3"}; 
public List<string> Source 
{ 
    get { return _source; } 
} 

Тогда определите одно свойство, которое удерживает выбранный элемент

string _theSelectedItem = null; 
public string TheSelectedItem 
{ 
    get { return _theSelectedItem; } 
    set { _theSelectedItem = value; } // NotifyPropertyChanged 
} 

Также не забудьте реализовать интерфейс INotifyPropertyChanged при настройке _source

+0

Это ближе всего к тому, с чем я столкнулся, и, я думаю, в зависимости от того, что вы хотели сделать с ComboBox, может быть решением (для кого-то еще). @ aks81, Спасибо за ваш ответ! –

+0

Добро пожаловать @AlistairTweed. – Sandesh

1

Если вы просто хотите, чтобы получить уведомление, когда текущие изменения пункт, почему бы не использовать инструменты которые уже являются частью WPF вместо всех этих зависимостей.

Сначала получите базовый вид своей коллекции и используйте на нем событие CurrentChanged.

ComboBoxList = new ObservableCollection<string>(); 
var view = CollectionViewSource.GetDefaultView(ComboBoxList); 
view.MoveCurrentTo(ComboBoxList[0]); 
view.CurrentChanged += new EventHandler(ComboBoxCurrentChanged); 

В вашем XAML вы просто связать свою коллекцию и установить IsSynchronizedWithCurrentItem истину.

<ComboBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ComboBoxList}"/> 
Смежные вопросы