我是WPF和MVVM的新手,我正在按照MVVM设计模式开发测试WPF应用程序。我的数据库有2个实体,卡片和部门。任何一张卡只能有一个部门,所以它是一对多的关系。
我已创建以下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&#39; datacontext当前正被设置为CardForm实例化的代码中的CardViewModel实例,但我将创建一个IoC容器或依赖注入。
除了ComboBox应该包含所有部门并且选择了Card实例中的当前部门(card.Department)之外,所有内容都正确绑定。这是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}" />
部门显示在组合框中,但卡的当前部门不是,如果我尝试更改它,我得到并且错误说&#34;无法添加具有已经存在的密钥的实体使用&#34;
所以,我的问题是,如何将这个组合框正确地绑定到我的ViewModel?
P.S。我知道填充ViewModel中的ObservableCollection<Department>
可能不是正确的方法,但我当时想不出更好的方法。如果您对此有任何建议,请告诉我。
此外,这是卡片型号:
[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");
}
}
}
答案 0 :(得分:0)
我在CardViewModel
中编辑了构造函数,将DataContext
作为参数进行了操作。这是新的CardViewModel
构造函数:
public CardViewModel(Card card, SybaseDatabaseContext myDB)
{
this.Card = card;
var query = from d in myDB.Departments
select d;
this.Departments = new ObservableCollection<Department>(query);
}
答案 1 :(得分:0)
我必须自己做一些研究。以为我会用一个自我回答的问题做出贡献,但发现这个当前开放的问题......
ComboBox
旨在成为一种文本框,将其可能的值限制在给定列表的内容中。该列表由ItemsSource
属性提供。 ComboBox
的当前值是SelectedValue
属性。通常,这些属性绑定到相应ViewModel的相关属性。
以下示例显示了有线ComboBox以及用于通过共享视图模型属性冗余查看TextBox
的当前值的ComboBox
控件。 (值得注意的是,当TextBox将共享属性更改为ComboBox
的值列表范围之外的值时,ComboBox
不会显示任何内容。)
注意:以下WPF / C#示例确实使用了代码隐藏,因此将ViewModel仅显示为视图的datacontext而不是partial class
,这是当使用带F#的WPF时的当前实现约束。
WPF XAML
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<m:MainWindowVM />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding SelectedString}" />
<ComboBox ItemsSource="{Binding MyList}" SelectedValue="{Binding SelectedString}" />
</StackPanel>
</Window>
C#ViewModel
using System.Collections.Generic;
using System.ComponentModel;
namespace WpfApplication1
{
public class MainWindowVM : INotifyPropertyChanged
{
string selectedString;
void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged == null) return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public string SelectedString
{
get { return selectedString; }
set
{
selectedString = value;
NotifyPropertyChanged("SelectedString");
}
}
public List<string> MyList
{
get { return new List<string> { "The", "Quick", "Brown", "Fox" }; }
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
默认情况下,ToString()用于解释列表中的对象。但是,ComboBox
提供DisplayMemberPath
和SelectedValuePath
属性,用于指定相应显示和存储值的特定对象属性的路径。这些路径是相对于列表对象元素的,因此路径为&#34; Name&#34;引用列表对象项上的名称。
&#34;备注&#34; this MSDN link部分解释了IsEditable
和IsReadOnly
ComboBox
属性的解释。