如何将AutoCompleteBox.PopulateComplete方法与MVVM范例结合使用?

时间:2012-11-26 17:23:53

标签: mvvm silverlight-4.0 silverlight-toolkit

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

现在,我正在尝试遵循MVVM的原则,通过该原则,viewmodel对视图本身一无所知。哪个好,因为我将自动填充框的Populating事件绑定到我的viewmodel 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视图?

1 个答案:

答案 0 :(得分:2)

如果您使用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();
        }
    }