SelectedItem / SelectedValueを更新していないように見えるComboBoxがあります。
ComboBox ItemsSourceは、一連のRAS電話帳エントリをCollectionViewとしてリストするViewModelクラスのプロパティにバインドされています。次に、ViewModelのSelectedItem
またはSelectedValue
別のプロパティに(別々に)バインドしました。データバインディングによって設定された値をデバッグするために、saveコマンドにメッセージボックスを追加しましたが、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
両方のNameプロパティであるため、オブジェクトの他のプロパティには影響しません。ConnectionViewModel。ComboBoxは、DataContextがViewModelインスタンスに設定されているWindowのにDataTemplate
適用されItemsControl
ます。
ComboBoxは項目のリストを正しく表示し、UIで問題なく選択できます。ただし、コマンドからメッセージボックスを表示すると、PhonebookEntryプロパティには、ComboBoxから選択された値ではなく、初期値が含まれています。他のTextBoxインスタンスは正常に更新され、MessageBoxに表示されます。
ComboBoxのデータバインドで何が不足していますか?多くの検索を実行しましたが、間違っていることを見つけることができません。
これは私が見ている動作ですが、私の特定のコンテキストでは何らかの理由で機能していません。
CollectionView
ConnectionViewModelのMainWindowViewModelがあります。MainWindowView.xamlファイルのコードビハインドで、DataContextをMainWindowViewModelに設定しました。MainWindowView.xamlは、ItemsControl
ConnectionViewModelのコレクションにバインドされています。ComboBoxとその他のTextBoxを保持するDataTemplateがあります。TextBoxは、を使用して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}" />
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は更新しません。私がやったことは本当に親ビューモデルを導入することだけであると考えると非常に混乱します。
私は現在、DataContextの子にバインドされたアイテムがその子をDataContextとして持っているという印象の下で作業しています。これを片づけるドキュメントを見つけることができません。
つまり、
ウィンドウ-> DataContext =
MainWindowViewModel ..Items-> Bound to DataContext.PhonebookEntries
.... Item- > DataContext = PhonebookEntry(暗黙的に関連付けられています)
それが私の仮定をよりよく説明するかどうかはわかりません(?)。
私の仮定を確認するには、TextBoxのバインディングを次のように変更します
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
そして、TextViewバインディングルート(DataContextと比較しています)がConnectionViewModelインスタンスであることを示します。
<
T として公開>
し、プロパティゲッターで_list.AsReadOnly()を使用して前述の方法と同様に公開しています。元のメソッドが期待していたとおりに機能しています。また、ItemsSourceバインディングが正常に機能しているときに、ViewModelのCurrentプロパティを使用して、ComboBoxで選択された項目にアクセスできたのではないかと思いました。それでも、ComboBoxes SelectedValue / SelectedItemプロパティをバインドするほど自然ではありません。