在我的WPF应用程序中,我使用WCF服务来获取数据。因此,在某些时候,我有一些“复杂”的对象,它们需要将DataContract作为一个整体传递给WPF应用程序。
当然,现在我需要响应更改,并且我在我的ViewModels上实现了INotifyPropertyChanged,但是由于一些对象实际上是DataContracts,所以我必须重新组合这些对象,以便它们实现INotifyPropertyChanged。
我觉得这里很乱。
我尝试做的是直接在DataContract定义上实现接口,但是我不能正确地对更改做出反应。
例如,如果双向数据绑定TextBox的文本被更改,我的ViewModel应该通过更改相应SQL表中的值(通过WCF服务)来响应它,但由于对象是在WCF端定义的,所以我不能在属性的setter中执行此操作。
现在,我要做的是订阅DataContracts的PropertyChanged事件,并使用反射来了解哪个属性发生了更改,以及它的新值。
但这些对象被保存在ObservableCollection<T>中,这是很多事件,它感觉非常脆弱……例如,如果我在集合中添加/删除一个元素呢?
我这样做(我认为这很糟糕):
foreach (ImageInfo imgi in (param.Images as ObservableCollection<ImageInfo>))
{
imgi.PropertyChanged += (sender, args) =>
{
object newValue = Tools.GetProperty((sender as ImageInfo), args.PropertyName);
};
}然后我会将它发送回WCF服务。
有没有更优雅的解决方案呢?我应该只在ViewModel上实现INotifyPropertyChanged,然后重新组合DataContracts吗?
谢谢!
发布于 2011-10-01 21:46:00
好的,经过一段时间的思考后,我现在这样实现了它,但它可能会改变,因为我会在下周一会见一位专家(如果他给我一个更好的想法,我会更新)。
1) WCF服务有一个DataContract,如:
[DataContract]
public class MyWcfData : INotifyPropertyChanged
{
public MyWcfData()
{
MyField = "";
}
[DataMember]
public string MyField;
[DataMember]
public string MyFieldModified;
}注意: INotifyPropertyChanged是以通常的方式实现的,我只是为了可读性而省略了它,因为我在这台计算机上没有我的代码片段。
在服务上调用GetMyData()时,它将返回该类的一个实例,其中只填充了"MyField“。MyFieldModified保留为null。
在我的DAL (所以是客户端)上,接收MyWcfData:
public class MyDAL
{
//... some init code
public MyWcfData GetMyWcfData()
{
MyWcfData newData = m_WcfService.GetMyData();
newData.MyFieldModified = newData.MyField;
return newData;
}
}这里的要点是,需要复制数据,以便我可以跟踪更改,并在最后只更新一次属性,即使用户更改了10次(我只是将每次都与原始值进行比较)。但是我不想通过网络发送重复的数据,所以在任何业务对象访问它之前,我在DAL中进行复制。
在我的视图的ViewModel上:
public class MyViewModel
{
//.. some init code
DelegateCommand<MyWcfData> _GetDataCommand;
public DelegateCommand<MyWcfData> GetDataCommand
{
get
{
if (_GetDataCommand == null)
_GetDataCommand = new DelegateCommand<MyWcfData>(GetData);
return _GetDataCommand;
}
}
public void GetData(MyWcfData param)
{
m_WcfData = m_DAL.GetMyWcfData();
}
}最后但并非最不重要的一点是,在我的XAML中,我绑定到TextBox中的MyFieldModified (双向绑定)。
然后,我使用System.Windows.Interactivity在TextChanged事件上调用DelegateCommand。
当最后一个命令被触发时,我将更改放入队列中(以跟踪更改顺序),并在用户按下Save按钮时将其发送回Wcf服务以实现数据持久化。
注意:我实际上使用了一个定制的ObservableQueue<T>,这样我就可以跟踪更改的数量,并通过绑定相应地启用保存按钮。我会写一篇关于它的博客文章,所以请继续关注;-)
Note2:我放弃了让它立即保存每一个微小的更改,即使在这种情况下它可以工作,因为它不是一个经常使用的功能,并且几乎没有预期的更改;但正如在其他答案中指出的那样,这是一种糟糕的做法。
发布于 2011-09-28 21:35:09
因此,您想要一个通过WCF服务器链接到数据库的实时系统?
如何创建Model对象,该对象的Get/Set方法与数据库交互?
public class MyModel : INotifyPropertyChanged
{
private IMyModelService service;
public int Id { get; set; }
public MyModel (IMyModelService wcfService, int id)
{
this.Id = id;
this.service = wcfService;
AutoMapper.Map<MyModelDTO, MyModel>(service.GetMyModel(this.Id), this);
}
public int SomeValue
{
get
{
return service.GetSomeValue(this.Id);
}
set
{
service.SetSomeValue(this.Id, value);
RaisePropertyChanged("SomeValue");
}
}
}您还可以在本地缓存对象属性,并使WCF服务调用异步,这可能会提高性能,尽管如果有多个人可以修改单个对象,则可能需要某种消息传递系统,以便在另一个用户更新属性时向客户端发出MyObject已更改的警报。
客户端上的ViewModel将负责创建模型,而不是WCF服务。
public class LoadObject(int id)
{
CurrentObject = new MyModel(serviceReference, id);
}https://stackoverflow.com/questions/7581687
复制相似问题