【发布时间】:2014-06-19 15:50:18
【问题描述】:
我是 WPF 和 MVVM 的新手,我正在按照 MVVM 设计模式开发一个测试 WPF 应用程序。我的数据库有 2 个实体,卡片和部门。任何卡片只能有 1 个部门,因此是一对多的关系。
为了绑定到视图,我创建了以下 ViewModel:
public class CardViewModel : INotifyPropertyChanged
{
public CardViewModel(Card card)
{
this.Card = card;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
builder.DataSource = ".\\SQLExpress";
builder.InitialCatalog = "TESTDB";
builder.IntegratedSecurity = true;
SybaseDatabaseContext myDB = new SybaseDatabaseContext(builder.ConnectionString);
var query = from d in myDB.Departments
select d;
this.Departments = new ObservableCollection<Department>(query);
}
private Card _Card;
private ObservableCollection<Department> _Departments;
public Card Card
{
get { return _Card; }
set
{
if (value != this._Card)
{
this._Card = value;
SendPropertyChanged("Card");
}
}
}
public ObservableCollection<Department> Departments
{
get { return _Departments; }
set
{
this._Departments = value;
SendPropertyChanged("Departments");
}
}
#region INPC
// Logic for INotify interfaces that nootify WPF when change happens
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
CardForms 的 datacontext 当前正在被实例化 CardForm 的代码中设置为 CardViewModel 的一个实例,但我将创建一个 IoC 容器或依赖注入。
除了应该包含所有部门并且选择了 Card 实例中的当前部门 (card.Department) 的 ComboBox 之外,所有内容都正确绑定。这是 ComboBox 的 XAML:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="350,64,0,0"
Name="comboBoxDepartment" VerticalAlignment="Top" Width="120"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Path=Departments}"
DisplayMemberPath="DepartmentName"
SelectedItem="{Binding Path=Card.Department, Mode=TwoWay}" />
部门显示在组合框中,但卡的当前部门不是,如果我尝试更改它,我会收到错误消息“无法添加具有已使用密钥的实体”。
所以,我的问题是,如何将这个组合框正确绑定到我的 ViewModel?
附:我知道在 ViewModel 中填充 ObservableCollection<Department> 可能不是正确的方法,但当时我想不出更好的方法。如果您对此也有任何建议,请告诉我。
另外,这是 Card 模型:
[Table(Name = "Card")]
public class Card : INotifyPropertyChanged, INotifyPropertyChanging
{
private string _CardID;
private string _Holder;
private Int16? _DepartmentNo;
[Column(UpdateCheck = UpdateCheck.WhenChanged)]
public string CardID
{
get
{
return this._CardID;
}
set
{
if (value != this._CardID)
{
SendPropertyChanging();
this._CardID = value;
SendPropertyChanged("CardID");
}
}
}
[Column(UpdateCheck = UpdateCheck.WhenChanged)]
public string Holder
{
get
{
return this._Holder;
}
set
{
if (value != this._Holder)
{
SendPropertyChanging();
this._Holder = value;
SendPropertyChanged("Holder");
}
}
}
[Column(CanBeNull = true, UpdateCheck = UpdateCheck.WhenChanged)]
public Int16? DepartmentNo
{
get
{
return this._DepartmentNo;
}
set
{
if (value != this._DepartmentNo)
{
SendPropertyChanging();
this._DepartmentNo = value;
SendPropertyChanged("DepartmentNo");
}
}
}
private EntityRef<Department> department;
[Association(Storage = "department", ThisKey = "DepartmentNo", OtherKey = "DepartmentNo", IsForeignKey = true)]
public Department Department
{
get
{
return this.department.Entity;
}
set
{
Department previousValue = this.department.Entity;
if (((previousValue != value)
|| (this.department.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this.department.Entity = null;
previousValue.Cards.Remove(this);
}
this.department.Entity = value;
if ((value != null))
{
value.Cards.Add(this);
this._DepartmentNo = value.DepartmentNo;
}
else
{
this._DepartmentNo = default(Nullable<short>);
}
this.SendPropertyChanged("Department");
}
}
}
【问题讨论】:
-
你能粘贴
Card代码吗? -
@kmatyaszek 当然,但这只是带有 getter 和 setter 的属性。它实现了 INotifyPropertyChanged。
-
@Sheridan 我已经编辑了问题以解释差异,请取消标记以便人们回答。
-
可能是因为我正在创建 2x DataContexts。一个用于模型,另一个用于从数据库中检索所有部门。我将尝试从同一个 ComboBox 中检索所有必须在 ComboBox 中的部门。
-
是的,就是这样。 DataContext 不能有 2 个不同的实例。我删除了
ViewModel中的声明,并将其作为参考传递。