【问题标题】:How can I marry AutoCompleteBox.PopulateComplete method with the MVVM paradigm?如何将 AutoCompleteBox.PopulateComplete 方法与 MVVM 范例结合起来?
【发布时间】:2012-11-26 17:23:53
【问题描述】:

设置如下: 我有一个由从 WCF 服务获取数据的视图模型填充的自动完成框。所以到目前为止它非常简单明了。

现在,我正在尝试遵循 MVVM 的原则,即视图模型对视图本身一无所知。这很好,因为我将自动完成框的填充事件绑定到我的视图模型via triggers and commands 的方法。

所以视图模型正在获取数据,而视图正在等待。还没有问题。

现在,视图模型获得了数据,我将结果集合传递给绑定到控件的 ItemSource 属性的属性。屏幕上什么也没有发生。

我去 MSDN 并找到官方批准的方式来处理这种情况 (http://msdn.microsoft.com/en-us/library/system.windows.controls.autocompletebox.populating(v=vs.95).aspx):

  • 将 MinimumPrefixLength 和 MinimumPopulateDelay 属性设置为 值大于默认值,以最大限度地减少对 Web 服务的调用。

  • 处理 Populating 事件并设置 PopulatingEventArgs.Cancel 属性为真。

  • 进行必要的处理并将 ItemsSource 属性设置为 所需的项目集合。

  • 调用 PopulateComplete 方法以指示 AutoCompleteBox 显示 下拉菜单。

现在我看到最后一步的一个大问题,因为我不知道如何从视图模型中调用视图上的方法,前提是他们不知道(也不应该知道!)任何关于彼此。

那么我到底应该如何在不违反 MVVM 原则的情况下从视图模型中调用 PopulateComplete 视图方法?

【问题讨论】:

    标签: mvvm silverlight-4.0 silverlight-toolkit


    【解决方案1】:

    如果您使用 Blend 的交互库,一个选项是为 AutoCompleteBox 附加 Behavior<T>

    public class AsyncAutoCompleteBehavior : Behavior<AutoCompleteBox>
    {
        public static readonly DependencyProperty SearchCommandProperty
            = DependencyProperty.Register("SearchCommand", typeof(ICommand), 
                  typeof(AsyncAutoCompleteBehavior), new PropertyMetadata(null));
    
        public ICommand SearchCommand
        {
            get { return (ICommand)this.GetValue(SearchCommandProperty); }
            set { this.SetValue(SearchCommandProperty, value); }
        }
    
        protected override void OnAttached()
        {
            this.AssociatedObject.Populating += this.PopulatingHook;
        }
    
        protected override void OnDetaching()
        {
            this.AssociatedObject.Populating -= this.PopulatingHook;
        }
    
        private void PopulatingHook(object sender, PopulatingEventArgs e)
        {
            var command = this.SearchCommand;
            var parameter = new SearchCommandParameter(
                    () => this.AssociatedObject
                              .Dispatcher
                              .BeginInvoke(this.AssociatedObject.PopulateComplete),
                    e.Parameter);
            if (command != null && command.CanExecute(parameter))
            {
                // Cancel the pop-up, execute our command which calls
                // parameter.Complete when it finishes
                e.Cancel = true;
                this.SearchCommand.Execute(parameter);
            }
        }
    }
    

    使用以下参数类:

    public class SearchCommandParameter
    {
        public Action Complete
        {
           get;
           private set;
        }
    
        public string SearchText
        {
           get;
           private set;
        }
    
        public SearchCommandParameter(Action complete, string text)
        {
            this.Complete = complete;
            this.SearchText = text;
        }
    }
    

    此时你需要做两件事:

    1. 连接行为

      <sdk:AutoCompleteBox MinimumPopulateDelay="250" MinimumPrefixLength="2" FilterMode="None">
          <i:Interaction.Behaviors>
              <b:AsyncAutoCompleteBehavior SearchCommand="{Binding Search}" />
          </i:Interaction.Behaviors>
      </sdk:AutoCompleteBox>
      
    2. 创建一个处理您的aysnc搜索的DelegateCommand。

      public class MyViewModel : ViewModelBase
      {
          public ICommand Search
          {
              get;
              private set;
          }
      
          private void InitializeCommands()
          {
              this.Search = new DelegateCommand<SearchCommandParamater>(DoSearch);
          }
      
          private void DoSearch(SearchCommandParameter parameter)
          {
              var client = new WebClient();
              var uri = new Uri(
                  @"http://www.example.com/?q="
                  + HttpUtility.UrlEncode(parameter.SearchText));
              client.DownloadStringCompleted += Downloaded;
              client.DownloadStringAsync(uri, parameter);
          }
      
          private void Downloaded(object sender, DownloadStringCompletedEventArgs e)
          {
              // Do Something with 'e.Result'
              ((SearchCommandParameter)e.UserState).Complete();
          }
      }
      

    【讨论】:

    • 您介意我问一下您从哪里获得 Silverlight 的 System.Threading.Tasks 吗?
    • 为什么您认为 SearchCommand 与异步交互有任何关系?我的意思是在 Execute 的主体中有对 WCF 服务的调用,但 Execute 没有任何要返回的内容,因此我无法通过命令的 Execute 方法将该 asnychrouns 调用的句柄传递给 WCF。总而言之,PopulateComplete 方法似乎在调用命令的 Execute 方法后立即被调用,而无需等待 WCF 的结果
    • @bonomo:您可以控制执行命令何时返回,但如果您不想这样做也可以。我将继续进行更改以消除对 TPL 的任何依赖。
    • 很抱歉,我没有检查您所做的更新。它与一个特殊的请求对象一起工作。谢谢!
    • 让它工作。 FilterMode 需要设置为“无”,请更新您的 XAML。其实我能做到,没关系。
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    相关资源
    最近更新 更多