我有一个组合框,似乎没有更新SelectedItem/SelectedValue。
ComboBox ItemsSource绑定到ViewModel类上的一个属性,该属性将一系列RAS电话簿条目作为CollectionView列出。然后我将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的Name属性。组合框位于DataTemplate
中,应用于窗口上的ItemsControl
,其DataContext已设置为ViewModel实例。
组合框可以正确地显示项目列表,我可以在UI中毫无问题地选择一个。然而,当我从命令中显示消息框时,PhonebookEntry属性仍然有初始值,而不是从组合框中选择的值。其他文本框实例更新良好,并显示在消息框中。
我错过了什么与数据绑定组合框?我做了很多搜索,似乎找不到任何我做错的地方。
这是我所看到的行为,但在我的特定环境中,由于某种原因,它不起作用。
我有一个MainWindowViewModel,它有一个ConnectionViewModels的CollectionView
。在MainWindowView中。xaml文件代码背后,我设置DataContext为MainWindowViewModel。MainWindowView。xaml有一个ItemsControl
绑定到ConnectionViewModels集合。我有一个数据模板,持有组合框以及其他一些文本框。文本框使用Text="{Binding Path=ConnectionName}"
直接绑定到ConnectionViewModel的属性。
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}" />
文本框都正确绑定,数据在它们和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。我找不到任何能证明这一点的文件。
也就是说,
< p >窗口→DataContext = MainWindowViewModel我不知道这是否能更好地解释我的假设(?)
为了确认我的假设,将TextBox的绑定更改为
<TextBox Text="{Binding Mode=OneWay}" Width="50" />
这将显示TextBox绑定根(我比较DataContext)是ConnectionViewModel实例。