我在使用C#的WPF应用程序中使用MVVM,并且在正确绑定ComboBox时遇到了问题。
这是我在XAML中的ComboBox行:
<ComboBox ItemsSource="{Binding Repository.Models}" SelectedValue="{Binding Repository.SelectedModel}" DisplayMemberPath="Name"></ComboBox>
这是我的存储库中有趣的部分:
class Repository : INotifyPropertyChanged
{
//init MVVM pattern
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ObservableCollection<Model> _models;
public ObservableCollection<Model> Models
{
get
{
return _models;
}
set
{
_models = value;
NotifyPropertyChanged("Models");
}
}
private Model _selectedModel;
public Model SelectedModel
{
get
{
return _selectedModel;
}
set
{
_selectedModel = value;
NotifyPropertyChanged("SelectedModel");
}
}
这是我的Model类中有趣的部分:
abstract class Model : INotifyPropertyChanged
{
//init MVVM pattern
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
因此,当我选择/更改组合框的不同项时,绑定到Repository.SelectedModel.Parameters的DataGrid会按照我的要求进行更新。 因为我知道,绑定确实有效!
当我重新启动应用程序并调试到我的存储库时,我看到有一个SelectedModel(在启动时反序列化),但ComboBox保持空白。但DataGrid确实显示了正确的数据。
所以绑定本身确实有效,但是对ComboBoxLabel的绑定在某种程度上失败了。
我尝试了很多事情,比如在SelectedItem和SelectedValue之间切换,在Binding和Binding Path之间,在IsSynchronizedWithCurrentItem之间切换为true和false,但到目前为止没有任何工作。
你知道我的错吗? 提前谢谢!修改 这是我的MainWindowViewModel的有趣部分:
class MainWindowViewModel : INotifyPropertyChanged
{
//init MVVM pattern
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private Repository _repository;
public Repository Repository
{
get
{
return _repository;
}
set
{
_repository = value;
NotifyPropertyChanged("Repository");
}
}
这是我的App.xaml.cs,我在其中初始化我的DataContext:
//init point of app
public partial class App : Application
{
private MainWindowViewModel mainWindowViewModel;
//gets fired as the app starts
protected override void OnStartup(StartupEventArgs e)
{
//create the ViewModel
mainWindowViewModel = new MainWindowViewModel();
//create the mainWindow
var mainWindow = new MainWindow();
mainWindow.DataContext = mainWindowViewModel;
//show the mainWindow
mainWindow.Show();
}
答案 0 :(得分:1)
在ComboBox中尝试SelectedItem而不是SelectedValue。
答案 1 :(得分:1)
当我重新启动应用程序并调试到我的存储库时,我发现有一个SelectedModel (在启动时反序列化)但是ComboBox保持空白。但DataGrid确实显示了正确的数据。
看起来反序列化就是问题所在。
您有一个反序列化的所选项目。这意味着创建了一个新的Model
实例,其中包含Name
的任何内容,Properties
即可。并且您在Model
中有一个ObservableCollection<Model>
个实例列表,这些实例显示在ComboBox中。
您向我们保证,至少有时,ComboBox.SelectedItem
绑定SelectedModel
,但由于某些原因,您问题中的代码会绑定ComboBox.SelectedValue
。那不行。以下是ComboBox.SelectedValue
的使用方式:
<ComboBox
ItemsSource="{Binding Repository.Models}"
SelectedValuePath="Name"
SelectedValue="{Binding SelectedModelName}"
/>
...您必须在viewmodel上拥有String SelectedModelName { get; set; }
属性。当选择更改时,Name
将为Model
的{{1}}属性分配该属性。但是你没有ComboBox
,而你却不想要它,所以忘掉SelectedModelName
。
返回SelectedValue
。 SelectedItem
从绑定中获取ComboBox
的值,并尝试在其Items列表中找到该确切对象。由于确切对象不在该列表中,因此它不会选择任何内容。 SelectedModel
中的某个项可能具有相同的名称且具有相同的Repository.Models
,但它与Properties
类的实际实例不同。 Model
并未查找ComboBox
中值相同的双胞胎;它寻找相同的对象。
SelectedItem
适用于SelectedModel.Properties
,因为DataGrid
不知道或不关心DataGrid
中的内容。你给它一个集合,这很好。
所以:如果你想反序列化Models
并让它具有任何意义,你需要做的是继续反序列化,但然后找到等价物 SelectedModel
中的项目(相同Repository.Models
,相同Name
),并将该实际对象实例分配给Properties
。
您可能想要超载SelectedModel
。 不要的。我这样做是为了解决同样的问题。在C#中不会产生最终的行为,并且会在你最不期望的时候咬你,因为你无形中改变了框架代码中发生的行为。我花了几天时间跟踪我创建的那些错误,我再也不会对自己这么做了。