silverlight - 在 silverlight 中使用 mvvm 进行异步调用

标签 silverlight mvvm c#-4.0

我正在尝试使用我的 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/

相关文章:

c# - Windows Phone 禁用应用程序栏按钮

WPF DataGrid 在代码中更新其 ItemsSource 时不更新 UI

javascript - 如何对一个 textarea 组件的文本值进行数据绑定(bind)并更新它?

asp.net - Json.Net 如何将 null 反序列化为空字符串?

.net - C# 中的方法重载和动态关键字

silverlight - 使用RIA Services域服务的EF4中的Include()无法加载!

silverlight - Name 和 x :Name? 有什么区别

c# - 反序列化对 Saml2SecurityToken 的 SAML2 响应时出错

c# - 无法从我的 Silverlight 应用程序调用 Assembly.GetName()

ios - 对于 UICollectionViewController 来说,正确的 MVVM 架构是什么