3

セットアップは次のとおりです。WCFサービスからデータを取得するビューモデルによって入力されているオートコンプリートボックスがあります。したがって、これまでのところ、これは非常に単純で単純です。

今、私は、ビューモデルがビュー自体について何も知らないというMVVMの原則に従おうとしています。オートコンプリートボックスのPopulatingイベントを、トリガーとコマンドを介してビューモデルのメソッドにバインドしたので、これは良いことです。

そのため、ビューが待機している間、ビューモデルはデータのフェッチに取り組んでいます。まだ問題ありません。

これで、ビューモデルがデータを取得し、結果のコレクションをコントロールのItemSourceプロパティにバインドされたプロパティに渡しました。画面には何も起こりません。

私はMSDNにアクセスし、この状況がどのように処理されるかについて公式に承認された方法を見つけます(http://msdn.microsoft.com/en-us/library/system.windows.controls.autocompletebox.populating(v=vs .95).aspx):

  • MinimumPrefixLengthプロパティとMinimumPopulateDelayプロパティをデフォルトよりも大きい値に設定して、Webサービスへの呼び出しを最小限に抑えます。

  • Populatingイベントを処理し、PopulatingEventArgs.Cancelプロパティをtrueに設定します。

  • 必要な処理を行い、ItemsSourceプロパティを目的のアイテムコレクションに設定します。

  • PopulateCompleteメソッドを呼び出して、AutoCompleteBoxにドロップダウンを表示するように通知します。

ビューモデルからビューのメソッドを呼び出す方法がわからないため、最後のステップで大きな問題が発生します。ただし、ビューモデルがお互いについて何も知らない(そして知らないはずです!)場合に限ります。

では、MVVMの原則を破ることなく、ビューモデルから呼び出されたPopulateCompleteメソッドのビューを取得するにはどうすればよいでしょうか。

4

1 に答える 1

2

BlendのInteractivityライブラリを使用する場合、次のオプションが1つ添付Behavior<T>されていAutoCompleteBoxます。

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;
    }
}

この時点で、次の2つのことを行う必要があります。

  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();
        }
    }
    
于 2012-11-26T17:54:56.773 に答える