我正在尝试使用我的 silverlight 应用程序调用 wcf 服务,但在理解模型如何将结果返回给 View 模型时遇到了一些麻烦。在我的 View 模型中,我有以下命令:
public DelegateCommand GetSearchResultCommand
{
get
{
if (this._getSearchResultCommand == null)
this._getSearchResultCommand = new DelegateCommand(GetSearchResultCommandExecute, CanGetSearchResultsCommandExecute);
return this._getSearchResultCommand;
}
}
private void GetSearchResultCommandExecute(object parameter)
{
this.SearchResults = this._DataModel.GetSearchResults(this.SearchTerm);
}
/// <summary>
/// Bindable property for SearchResults
/// </summary>
public ObservableCollection<QueryResponse> SearchResults
{
get
{
return this._SearchResults;
}
private set
{
if (this._SearchResults == value)
return;
// Set the new value and notify
this._SearchResults = value;
this.NotifyPropertyChanged("SearchResults");
}
}
然后在我的模型中,我有以下代码
public ObservableCollection<QueryResponse> GetSearchResults(string searchQuery)
{
//return type cannot be void needs to be a collection
SearchClient sc = new SearchClient();
//******
//TODO: stubbed in placeholder for Endpoint Address used to retreive proxy address at runtime
// sc.Endpoint.Address = (clientProxy);
//******
sc.QueryCompleted += new EventHandler<QueryCompletedEventArgs>(sc_QueryCompleted);
sc.QueryAsync(new Query { QueryText = searchQuery });
return LastSearchResults;
}
void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
this.LastSearchResults = results;
}
当我在模型中插入断点时,我会看到查询的执行位置并在模型中返回结果(this.LastSearchResults = results),但是我似乎无法让这个集合更新/通知 View 模型的结果。我只使用一个方法和虚拟类生成并运行了一个类似的测试,它似乎可以工作,所以我怀疑问题是由于异步调用/线程造成的。我在 ViewModel 中有 INotifyPropertyChanged 来同步 View 和 ViewModel。我还需要在模型中实现 INotifyPropChng 吗?我是 mvvm 的新手,所以任何关于我应该如何解决这个问题的帮助/示例将不胜感激。
谢谢,
更新
在进一步的测试中,我将 INotifyPropertyChanged 添加到模型中,并将 Completed 事件更改如下:
void sc_QueryCompleted(object sender, QueryCompletedEventArgs e)
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
//this.LastSearchResults = results;
SearchResults = results;
}
关注搜索结果,我现在看到它已使用 WCF 的结果进行了更新。我的问题仍然存在,这是正确的方法吗?它现在似乎可以工作,但是我很好奇我是否遗漏了其他东西,或者我不应该将 INotify 放在模型中。
谢谢,
最佳答案
我发现最好将我的 WCF 服务封装在额外的服务类层中。这使我可以更轻松地对我的 ViewModel 进行单元测试。执行此操作时有几种模式,尽管这是我使用过的最简单的模式。该模式是创建一个与服务调用的定义相匹配的方法,但也包含一个可以在服务调用完成后调用的 Action。
public class Service : IService
{
public void GetSearchResults(string searchQuery, Action<ObservableCollection<QueryResponse>> reply)
{
//return type cannot be void needs to be a collection
SearchClient sc = new SearchClient();
//******
//TODO: stubbed in placeholder for Endpoint Address used to retreive proxy address at runtime
// sc.Endpoint.Address = (clientProxy);
//******
sc.QueryCompleted += (s,e) =>
{
ObservableCollection<QueryResponse> results = new ObservableCollection<QueryResponse>();
results.Add(e.Result);
reply(results);
};
sc.QueryAsync(new Query { QueryText = searchQuery });
}
}
您还可以提供 ViewModel 可以使用的接口(interface)。这使得单元测试更加容易,尽管是可选的。
public interface IService
{
void GetSearchResults(string searchQuery, Action<ObservableCollection<QueryResponse>> reply);
}
您的 ViewModel 将如下所示:
public class MyViewModel : INotifyPropertyChanged
{
private IService _service;
public MyViewModel()
: this(new Service())
{ }
public MyViewModel(IService service)
{
_service = service;
SearchResults = new ObservableCollection<QueryResponse>();
}
private ObservableCollection<QueryResponse> _searchResults
public ObservableCollection<QueryResponse> SearchResults
{
get { return _searchResults; }
set
{
_searchResults = value;
NotifyPropertyChanged("SearchResults");
}
}
public void Search()
{
_service.GetSearchResults("abcd", results =>
{
SearchResults.AddRange(results);
});
}
protected void NotifyPropertyChanged(string property)
{
var handler = this.PropertyChanged;
if(handler != null)
handler(new PropertyChangedEventArgs(property));
}
}
将您的服务调用封装到这样的另一个类中的另一个原因是,它可以为诸如日志记录和错误处理之类的事情提供一个单一的位置。这样,您的 ViewModel 本身就不需要处理与服务特别相关的那些事情。
关于silverlight - 在 silverlight 中使用 mvvm 进行异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5950264/