Wpf 可观测数据契约和双向绑定

Wpf 可观测数据契约和双向绑定,wpf,wcf,architecture,inotifypropertychanged,Wpf,Wcf,Architecture,Inotifypropertychanged,在我的WPF应用程序中,我使用WCF服务获取数据。 因此,很自然,在某个时候,我有一些“复杂”的对象,它们需要将DataContract作为一个整体传递给WPF应用程序 当然,现在我需要响应更改,并在我的ViewModels上实现INotifyPropertyChanged,但是由于某些对象实际上是DataContract,我必须重新组合这些对象,以便它们实现INotifyPropertyChanged 我觉得很乱 我试图直接在DataContract定义上实现接口,但无法对更改做出正确反应。

在我的WPF应用程序中,我使用WCF服务获取数据。 因此,很自然,在某个时候,我有一些“复杂”的对象,它们需要将
DataContract
作为一个整体传递给WPF应用程序

当然,现在我需要响应更改,并在我的ViewModels上实现
INotifyPropertyChanged
,但是由于某些对象实际上是DataContract,我必须重新组合这些对象,以便它们实现INotifyPropertyChanged

我觉得很乱

我试图直接在DataContract定义上实现接口,但无法对更改做出正确反应。
例如,如果双向数据绑定的
TextBox
的文本发生了更改,则我的ViewModel应该通过更改相应SQL表中的值(通过WCF服务)对其作出反应,但由于对象是在WCF端定义的,因此我无法在属性的setter中执行此操作

我现在要做的是订阅DataContracts的PropertyChanged事件,并使用反射来了解哪个属性发生了更改及其新值。
但是这些对象被保存在一个
可观察的集合中
,这是很多事件,它感觉非常脆弱。。。例如,如果我从集合中添加/删除一个元素会怎么样

我是这样做的(我认为这很糟糕):

foreach(ImageInfo imgi in(param.Images as ObservableCollection))
{
imgi.PropertyChanged+=(发送方,参数)=>
{
object newValue=Tools.GetProperty((发送方为ImageInfo),args.PropertyName);
};
}
然后我会将其发送回WCF服务

public class LoadObject(int id)
{
    CurrentObject = new MyModel(serviceReference, id);
}
有没有更优雅的解决方案?我是否应该仅在ViewModel上实现INotifyPropertyChanged,并重新组合DataContracts


谢谢

那么您想要一个由WCF服务器链接到数据库的实时系统

如何创建模型对象,这些对象的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");
        }
    }
}

好吧,经过一段时间的思考,我现在就这样实现了它,但它可能会改变,因为我下周一会与一位专家会面(如果他给我一个更好的想法,我会更新)

1) WCF服务有一个DataContract,例如:

[DataContract]
public class MyWcfData : INotifyPropertyChanged
{
    public MyWcfData()
    {
       MyField = "";
    }

    [DataMember]
    public string MyField;

    [DataMember]
    public string MyFieldModified;
}
注意:INotifyPropertyChanged是以通常的方式实现的,我只是为了可读性而将其省略,因为我的代码片段没有放在这台计算机上

在服务上调用GetMyData()时,它返回该类的一个实例,只填充“MyField”。MyFieldModified保留为空。

在接收MyWcfData的我的DAL(so客户端)上:

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();
        }  
}
公共类MyViewModel
{
//…一些初始化代码
DelegateCommand _GetDataCommand;
公共DelegateCommand GetDataCommand
{
得到
{
如果(_GetDataCommand==null)
_GetDataCommand=新的DelegateCommand(GetData);
返回_GetDataCommand;
}
}        
public void GetData(MyWcfData参数)
{
m_WcfData=m_DAL.GetMyWcfData();
}  
}
最后但并非最不重要的一点是,在我的XAML中,我绑定到
文本框中的
MyFieldModified
(双向绑定)

然后使用
System.Windows.Interactivity
TextChanged
事件时调用
DelegateCommand

当最后一个命令被触发时,我将更改放入队列(以跟踪更改顺序),并在用户按下保存按钮时将其发送回Wcf服务以实现数据持久性

注意:我实际上使用了一个定制的
ObservableQueue
,这样我可以跟踪更改的数量,并通过绑定相应地启用保存按钮。我会写一篇关于它的博文,请继续关注;-)


注2:我放弃了让它保存即时所做的每一个微小更改,即使在这种情况下,它也会起作用,因为它不是一个经常使用的功能,而且预期的更改很少;但正如其他答案所指出的,这是一种不好的做法。

我可以解释我是如何做到这一点的。数据契约是普通对象。viewmodel接收数据协定作为构造函数参数,并填写自己的属性。用户单击“保存”按钮后,视图模型会收集新值,构造新的数据协定并将其发送到服务。是的,但我没有“保存”按钮,每次属性更改时,我都需要调用该服务以反映数据库中的更改。这更难,而且会增加数据库的工作负载。但如果我有这样的要求,我也会这样做:创建新的数据契约并将其发送到服务,即使数据契约只因一个属性不同。如果要向RaisePropertyChanged方法添加额外的方法调用,则可以处理实时更改。在主视图模型中调用Save方法,或者从子项中使用某种Messenger类。这正是我的想法,只是我不知道如何构建该类。当ViewModel请求数据时,该对象由WCF服务创建,并且该WCF对象(契约)实现INotifyPropertyChanged。它不能自称。你需要合成上面的代码才能工作。该应用程序将由几十个用户同时使用,但WCF双工不在主题范围内(稍后再讨论)。@Baboon I实际上会让WCF与数据传输对象(DTO)一起工作,并使用类似于
AutoMapper
的东西将DTO映射到模型。因此ViewModel实际上将负责创建模型obj
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();
        }  
}