场景:需要从web服务收集对象集合,并将其显示在GUI中。该对象包含对另一个对象(外键)的引用,我也需要表示这个相关的对象。
我提出了两种可能的选择,它们各自都有缺点:
- 发送整个相关对象
- 只发送外键并检索查询另一个集合(以前存储在本地)的相关对象
1st选项使数据绑定(我在客户端使用WPF)直接进行,尽管它在通信中引入了大量开销(特别是在相同的相关对象多次出现的情况下)。因此,这似乎不是应该走的路。
第二个选项实现了更小的消息,看起来这是一条路要走但是,我找不到执行与此相关对象的数据绑定的方法。
让我用一个例子来澄清这个问题:
对象->房间||相关对象->建筑||本地存储的集合->建筑
来自Web服务的消息包含房间属性(比如"name"、"size"…)和"BuildingId"。我希望能够在UI中显示(通过数据绑定自动显示)来自建筑的信息,而不仅仅是"BuildingId"。因此,我必须查询"Buldings"集合才能获得正确的Building Object,然后使用其属性填充UI,这似乎是合乎逻辑的。
所以,我的问题是:
- 如何通过WPF中的数据绑定实现这一点我想有一种自动实现的方法。不是吗
- 我是否缺少任何底层概念(与数据绑定相关)?我是.NET堆栈的新手,所以这可能比我看起来更容易
谢谢大家!;)
附言:任何能为我指明正确方向的文件/链接都将不胜感激;)
尝试将您的两个选项与.Net/WPF世界中的典型方法联系起来(按相反顺序):
方法2:模型-视图-视图模型方法(MVVM)可能是一种方法。DTO旨在使用WCF(模型)优化消息传递。MVVM原则建议您不应该用诸如数据绑定之类的问题来污染它们。一个单独的类ViewModel对此负责,还可以管理诸如使用缓存查找将基元标识符(例如BuildingId)映射到对象的可绑定表示等问题。然后,您的WPF视图绑定到ViewModel,而不是绑定到DTO。
如果您想追求这个选项,请了解MVVM的概念,然后您可能需要考虑一个工具来提供帮助。(我发现Caliburn Micro非常出色,但也有一些适合WPF)
方法1:这是一种更简单的方法,意味着您编写WCF服务,以便它将预制的ViewModel从服务器提供给客户端(即DTO和ViewModel是一回事)。正如您已经观察到的,由于构建ViewModels的责任是在服务器上完成的,因此在传输冗余数据时可能会遇到问题。这种方法还意味着客户端和服务器是紧密耦合的——每个DTO/ViewModel都设计用于特定的视图。
最终,最佳方法取决于应用程序的要求。如果你正在寻找一种简单的方法,即你不关心一些冗余的数据通信,只想尽快找到解决方案,那么方法1可能更可取。
但是,如果您需要为其他客户端提供服务,或者由于其他原因避免客户端和服务器耦合很重要,或者需要高效通信,则应考虑MVVM方法。
我在Room对象上有一个名为Building的属性,该属性最初可以为空(null),但稍后在加载Building对象时设置。您的房间对象应该实现INotifyPropertyChanged
,它将在对象最终加载时通知UI,并导致所有绑定刷新。
示例INotifyPropertyChanged实现:
private bool _Active;
public bool Active
{
get { return _Active; }
set
{
if (_Active == value)
return;
_Active = value;
OnPropertyChanged("Active");
}
}
#region PropertyChanged Implementation
// Code Below Copied From : http://www.codeproject.com/KB/cs/PropertyNotifyPart1.aspx
/// <summary>
/// Raises the <see cref="E:PropertyChanged"/> event.
/// </summary>
/// <param name="propertyName">
/// Name of the property that changed.
/// </param>
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
OnPropertyChanged(e);
}
/// <summary>
/// Raises the <see cref="E:PropertyChanged"/> event.
/// </summary>
/// <param name="e">
/// The <see cref="PropertyChangedEventArgs"/> instance
/// containing the event data.
/// </param>
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler temp = this.PropertyChanged;
if (null != temp)
temp(this, e);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler temp = this.PropertyChanged;
if (null != temp)
temp(sender, e);
}
#endregion