我有一个ComboBox,它似乎没有更新SelectedItem / SelectedValue。
ComboBox ItemsSource绑定到ViewModel类上的一个属性,该类将一堆RAS电话簿条目作为CollectionView列出。然后,我(在不同的时间)将ViewModel 的SelectedItem
或绑定SelectedValue
到了另一个属性。我已经在保存命令中添加了一个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}" />
我只是在实际字符串值兴趣显示在组合框,而不是对象,因为这任何其他属性是我需要跨传递给RAS时,我想使VPN连接,因此价值DisplayMemberPath
和SelectedValuePath
是双方的名称属性ConnectionViewModel。ComboBox在DataTemplate
应用于ItemsControl
DataContext已设置为ViewModel实例的Window上。
ComboBox可以正确显示项目列表,并且我可以在UI中选择一个项目而没有问题。但是,当我从命令显示消息框时,PhonebookEntry属性中仍具有初始值,而不是ComboBox中的选定值。其他TextBox实例正在更新,并且显示在MessageBox中。
我对数据绑定ComboBox缺少什么?我已经进行了很多搜索,但似乎找不到我做错的任何事情。
这是我所看到的行为,但是由于某种原因,在我的特定情况下它无法正常工作。
我有一个MainWindowViewModel,其中有一个CollectionView
ConnectionViewModels。在后面的MainWindowView.xaml文件中,我将DataContext设置为MainWindowViewModel。MainWindowView.xaml具有ItemsControl
对ConnectionViewModels集合的绑定。我有一个包含ComboBox以及其他一些TextBoxes的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; }
}
}
}
如果运行该示例,您将得到我正在谈论的行为。当您编辑文本框时,它会很好地更新其绑定,但组合框却不会。真正使我感到困惑的是,我引入了父级ViewModel。
我目前的工作印象是,绑定到DataContext的子项的项目具有该子项作为其DataContext。我找不到任何一种可以清除这种情况的文档。
即
窗口-> DataContext = MainWindowViewModel
..Items->绑定到DataContext.PhonebookEntries
.... Item- > DataContext = PhonebookEntry(隐式关联)
我不知道这是否可以更好地解释我的假设(?)。
为了确认我的假设,将TextBox的绑定更改为
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
这将显示TextBox绑定根(我正在与DataContext进行比较)是ConnectionViewModel实例。
<
T>
并在属性getter中公开,与您提到的方式类似。正如我希望的原始方法那样,它正在工作。另外,我想到,虽然ItemsSource绑定工作正常,但我可以只使用ViewModel中的Current属性来访问ComboBox中的所选项目。但是,它不像绑定ComboBoxes SelectedValue / SelectedItem属性那样自然。