2013-10-27 15 views
9

Tôi mới dùng C# và MVVM, và tôi đã dành cả ngày cố gắng lấy giá trị ComboBox cho ViewModel của tôi trên SelectionChanged. Tôi đã cố gắng tìm nó bằng cách sử dụng một trong hai CallMethodAction hoặc InvokeCommandAction với các nguồn lực:WPF - MVVM: Giá trị ComboBox sau khi chọnChuyển đổi

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

Vấn đề của tôi là rằng cả hai phương pháp này trả về giá trị của ComboBox trước khi nó đã thay đổi . Bất kỳ ai có thể giải thích cách nhận giá trị sau thay đổi?

Tôi đã dành hàng giờ tìm kiếm thông qua SO và Google để có giải pháp, vì vậy tôi tự hỏi liệu những người khác cũng vậy. Mọi lời khuyên sẽ được đánh giá cao!

Mã của tôi là dưới đây:

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: Giải pháp của tôi

Hóa ra tôi không hiểu Binding cũng đủ và thay vào đó đã cố gắng để thực hiện một cái gì đó đơn giản theo một cách khá phức tạp! Thay vì sử dụng các phụ thuộc, tôi đã đạt được những gì tôi cần bằng cách sử dụng các ràng buộc thường xuyên. Ví dụ: tôi đã gắn một số TextBox vào số SelectedIndex của số ComboBox, được cập nhật bằng cách sử dụng 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

Nếu tôi hiểu những gì bạn đang cố gắng làm, tôi nghĩ điều này sẽ giúp http://stackoverflow.com/questions/4765362/mvvm-combobox -ràng buộc – kenny

+0

Tôi sẽ chỉ thả một ý tưởng cho bạn. Làm thế nào về bạn ràng buộc SelectedItems bất động sản cho một tài sản trong ViewModel của bạn với chế độ ràng buộc TwoWay? Không cần nghe sự kiện SelectionChanged hoặc tạo lệnh. Bất cứ khi nào giá trị SelectedItems được thay đổi, bạn sẽ nhận được thông báo bên trong setter của thuộc tính của bạn trong ViewModel. Hãy dùng thử. –

+0

. Hãy thử một cái gì đó như thế này. – srsyogesh

Trả lời

19

Tại sao không làm điều đó một cách đơn giản hơn

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

Trong ViewModel của bạn tuyên bố các mục combo box và sử dụng một tài sản "Nguồn" để trở về nó để xem

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

Sau đó, xác định một thuộc tính chứa mục đã chọn

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

Cũng đừng quên triển khai giao diện INotifyPropertyChanged khi thiết lập _source

+0

Điều này là gần nhất với những gì tôi đã kết thúc với, và tôi đoán, tùy thuộc vào những gì bạn muốn làm với ComboBox, có thể là giải pháp (cho người khác). @ aks81, Cảm ơn câu trả lời của bạn! –

+0

Bạn được chào đón @AlistairTweed. – Sandesh

1

Nếu bạn chỉ muốn được thông báo khi thay đổi mục hiện tại của bạn, tại sao không sử dụng công cụ đã là một phần của WPF thay vì tất cả những phụ thuộc này.

Trước tiên, hãy xem chế độ xem cơ bản về bộ sưu tập của bạn và sử dụng sự kiện Hiện tại được thay đổi trên đó.

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

Trong xaml bạn chỉ cần ràng buộc bộ sưu tập của mình và đặt IsSynchronizedWithCurrentItem thành true.

<ComboBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ComboBoxList}"/> 
Các vấn đề liên quan