以下是设置: 我有一个自动完成框,由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视图?
答案 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;
}
}
此时你需要做两件事:
连接行为
<sdk:AutoCompleteBox MinimumPopulateDelay="250" MinimumPrefixLength="2" FilterMode="None">
<i:Interaction.Behaviors>
<b:AsyncAutoCompleteBehavior SearchCommand="{Binding Search}" />
</i:Interaction.Behaviors>
</sdk:AutoCompleteBox>
创建一个处理您的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();
}
}