SelectedItem/SelectedValue を更新していないように見える ComboBox があります。
ComboBox ItemsSource は、一連の RAS 電話帳エントリを CollectionView として一覧表示する ViewModel クラスのプロパティにバインドされています。次に、SelectedItem
またはの両方SelectedValue
を ViewModel の別のプロパティに (別々の時間に) バインドしました。データバインディングによって設定された値をデバッグするために保存コマンドに MessageBox を追加しましたが、SelectedItem
/SelectedValue
バインディングが設定されていません。
ViewModel クラスは次のようになります。
public ConnectionViewModel
{
private readonly CollectionView _phonebookEntries;
private string _phonebookeEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
}
_phonebookEntries コレクションは、コンストラクターでビジネス オブジェクトから初期化されています。ComboBox XAML は次のようになります。
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
ComboBox に表示される実際の文字列値のみに関心があります。オブジェクトの他のプロパティには関心がありません。これは、VPN 接続を確立するときに RAS に渡す必要がある値であるためDisplayMemberPath
ですSelectedValuePath
。 ConnectionViewModel。ComboBox は、DataContext が ViewModel インスタンスに設定されている Window にDataTemplate
適用されます。ItemsControl
ComboBox はアイテムのリストを正しく表示し、UI で問題なくアイテムを選択できます。ただし、コマンドからメッセージ ボックスを表示すると、PhonebookEntry プロパティには ComboBox から選択された値ではなく、初期値が含まれています。他の TextBox インスタンスは正常に更新されており、MessageBox に表示されています。
ComboBox のデータバインドで何が欠けていますか? 私は多くの検索を行ってきましたが、間違っていることは何も見つからないようです。
これは私が見ている動作ですが、私の特定のコンテキストでは何らかの理由で機能していません。
CollectionView
ConnectionViewModelsを持つ MainWindowViewModel があります。MainWindowView.xaml ファイルの分離コードで、DataContext を MainWindowViewModel に設定します。MainWindowView.xaml には、ItemsControl
ConnectionViewModels のコレクションへのバインドがあります。ComboBox と他のいくつかの TextBoxes を保持する DataTemplate があります。TextBoxes は、 を使用して ConnectionViewModel のプロパティに直接バインドされますText="{Binding Path=ConnectionName}"
。
public class ConnectionViewModel : ViewModelBase
{
public string Name { get; set; }
public string Password { get; set; }
}
public class MainWindowViewModel : ViewModelBase
{
// List<ConnectionViewModel>...
public CollectionView Connections { get; set; }
}
XAML コード ビハインド:
public partial class Window1
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
次に XAML:
<DataTemplate x:Key="listTemplate">
<Grid>
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
<TextBox Text="{Binding Path=Password}" />
</Grid>
</DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource listTemplate}" />
TextBoxes はすべて正しくバインドされ、データは TextBox と ViewModel の間で問題なく移動します。機能していないのは ComboBox だけです。
PhonebookEntry クラスに関するあなたの仮定は正しいです。
私が行っている仮定は、DataTemplate で使用される DataContext がバインディング階層を介して自動的に設定されるため、ItemsControl
. それは私には少しばかげているように思えます。
上記の例に基づいて、問題を実証するテスト実装を次に示します。
XAML:
<Window x:Class="WpfApplication7.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="itemTemplate">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=Name}" Width="50" />
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}"
Width="200"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=Connections}"
ItemTemplate="{StaticResource itemTemplate}" />
</Grid>
</Window>
分離コード:
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}
public class PhoneBookEntry
{
public string Name { get; set; }
public PhoneBookEntry(string name)
{
Name = name;
}
}
public class ConnectionViewModel : INotifyPropertyChanged
{
private string _name;
public ConnectionViewModel(string name)
{
_name = name;
IList<PhoneBookEntry> list = new List<PhoneBookEntry>
{
new PhoneBookEntry("test"),
new PhoneBookEntry("test2")
};
_phonebookEntries = new CollectionView(list);
}
private readonly CollectionView _phonebookEntries;
private string _phonebookEntry;
public CollectionView PhonebookEntries
{
get { return _phonebookEntries; }
}
public string PhonebookEntry
{
get { return _phonebookEntry; }
set
{
if (_phonebookEntry == value) return;
_phonebookEntry = value;
OnPropertyChanged("PhonebookEntry");
}
}
public string Name
{
get { return _name; }
set
{
if (_name == value) return;
_name = value;
OnPropertyChanged("Name");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainWindowViewModel
{
private readonly CollectionView _connections;
public MainWindowViewModel()
{
IList<ConnectionViewModel> connections = new List<ConnectionViewModel>
{
new ConnectionViewModel("First"),
new ConnectionViewModel("Second"),
new ConnectionViewModel("Third")
};
_connections = new CollectionView(connections);
}
public CollectionView Connections
{
get { return _connections; }
}
}
}
その例を実行すると、私が話している動作が得られます。TextBox は、編集時にバインディングを適切に更新しますが、ComboBox は更新しません。私が実際に行った唯一のことは、親ViewModelを導入することだけなので、非常に混乱しています。
私は現在、DataContext の子にバインドされたアイテムがその DataContext としてその子を持っているという印象の下で働いています。これを何らかの方法で解決するドキュメントが見つかりません。
すなわち、
Window -> DataContext =
MainWindowViewModel ..Items -> DataContext.PhonebookEntries にバインド
....Item -> DataContext = PhonebookEntry (暗黙的に関連付け)
それが私の仮定をよりよく説明するかどうかはわかりません(?)。
私の仮定を確認するために、TextBox のバインディングを次のように変更します。
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
これにより、TextBox バインディング ルート (DataContext と比較しています) が ConnectionViewModel インスタンスであることがわかります。