私はC#とMVVMを使い始めたばかりで、ComboBox
のSelectionChanged
の値をViewModelに取得しようと一日中費やしてきました。 CallMethodAction
またはInvokeCommandAction
をリソースとともに使用してそれを把握することができました。
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);
}
}
}
編集:私の解決策
私はBinding
を十分に理解しておらず、代わりにかなり複雑な方法で単純なものを実装しようとしていたことがわかりました!依存関係を使用する代わりに、通常のバインディングを使用して必要なものを実現しました。例として、TextBox
をSelectedIndex
のComboBox
にバインドしました。これはINotifyPropertyChanged
を使用して更新されます。
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));
}
}
}
それをもっと簡単な方法でやってみませんか
<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; }
}
次に、選択したアイテムを保持する1つのプロパティを定義します
string _theSelectedItem = null;
public string TheSelectedItem
{
get { return _theSelectedItem; }
set { _theSelectedItem = value; } // NotifyPropertyChanged
}
また、_sourceを設定するときにINotifyPropertyChangedインターフェイスを実装することを忘れないでください。
現在のアイテムが変更されたときに通知を受け取りたいだけの場合は、これらすべての依存関係の代わりに、すでにWPFの一部であるツールを使用しないでください。
まず、基になるビューをコレクションに取得し、それにCurrentChangedイベントを使用します。
ComboBoxList = new ObservableCollection<string>();
var view = CollectionViewSource.GetDefaultView(ComboBoxList);
view.MoveCurrentTo(ComboBoxList[0]);
view.CurrentChanged += new EventHandler(ComboBoxCurrentChanged);
Xamlでコレクションをバインドし、IsSynchronizedWithCurrentItem
をtrueに設定します。
<ComboBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding ComboBoxList}"/>