UWP 绑定到 MVVM 中的 AutoSuggestBox

Posted

技术标签:

【中文标题】UWP 绑定到 MVVM 中的 AutoSuggestBox【英文标题】:UWP Binding to AutoSuggestBox in MVVM 【发布时间】:2016-04-09 18:59:47 【问题描述】:

我正在 UWP 中调用 AutoSuggestBox 控件的 QuerySubmitted 命令。 该命令绑定到视图模型中的 ICommand。 问题是它需要接受纯 UI 的 AutoSuggestBoxQuerySubmittedEventArgs,它在 MVVM 中是不可接受的。

我的代码是这样的:

<AutoSuggestBox Name="SearchAutoSuggestBox"
                PlaceholderText="Search by keywords"
                QueryIcon="Find"
                >
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="QuerySubmitted">
            <core:InvokeCommandAction Command="x:Bind ViewModel.SearchCommand" />
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</AutoSuggestBox>

我的视图模型看起来像这样:

public DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs> SearchCommand  get; 

public MainPageViewModel()

    SearchCommand = new DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs>(ExecuteMethod);


private void ExecuteMethod(AutoSuggestBoxQuerySubmittedEventArgs o)

    // CODE HERE

ofcours AutoSuggestBoxQuerySubmittedEventArgs 在视图模型中是不可接受的。 寻找替代品... 同样适用于 SuggestionChosen...

【问题讨论】:

EventTriggerBehavior 的 MSDN 页面表示仅支持事件的子集,而 QuerySubmitted 不是其中之一。您是否为此实施了新行为? 【参考方案1】:

InvokeCommandAction 有一个名为 InputConverter 的参数,您可以使用该参数将事件 args 转换为可以传递给 ViewModel 的其他参数。

首先创建一个 IValueConverter 类以从事件参数中提取您需要的内容,如下所示:-

public class AutoSuggestQueryParameterConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, string language)
       
          // cast value to whatever EventArgs class you are expecting here
          var args = (AutoSuggestBoxQuerySubmittedEventArgs)value;
          // return what you need from the args
          return (string)args.ChosenSuggestion;
       

然后像这样在您的 XAML 中使用该转换器:

<Page.Resources>
     <converters:AutoSuggestQueryParameterConverter x:Key="ArgsConverter" />
</Page.Resources>

<AutoSuggestBox Name="SearchAutoSuggestBox"
            PlaceholderText="Search by keywords"
            QueryIcon="Find">
    <interactivity:Interaction.Behaviors>
      <core:EventTriggerBehavior EventName="QuerySubmitted">
        <core:InvokeCommandAction 
              Command="x:Bind ViewModel.SearchCommand"
              InputConverter="StaticResource ArgsConverter" />
      </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</AutoSuggestBox>

最后在您的视图模型中更改您的命令以接受字符串作为参数。所以你的虚拟机里会有以下内容:

public DelegateCommand<string> SearchCommand  get; 

public MainPageViewModel()

    SearchCommand = new DelegateCommand<string>(ExecuteMethod);


private void ExecuteMethod(string o)

    // CODE HERE

【讨论】:

【参考方案2】:

您可以将搜索字符串(文本属性)绑定到视图模型属性,并将事件绑定到无参数方法。这样视图模型就不必处理 UI 对象了:

XAML:

<AutoSuggestBox Header="What's your name?"
                TextChanged="x:Bind ViewModel.FilterUsuals"
                QuerySubmitted="x:Bind ViewModel.ProcessQuery"
                SuggestionChosen="x:Bind ViewModel.ProcessChoice"
                ItemsSource="x:Bind ViewModel.Usuals, Mode=OneWay"
                Text="x:Bind ViewModel.SearchText, Mode=TwoWay"
                QueryIcon="Find" />

后面的代码:

public class MainPageViewModel : SomeViewModelBaseClass

    /* Boilerplate code and constructor not included */

    private string _SearchText;
    public string SearchText /* getter and setter INotyfyPropertyChange compliant */ 

    private List<string> _Usuals; // Initialized on constructor
    public string Usuals /* getter and setter INotyfyPropertyChange compliant */ 


    public void FilterUsuals()
    
        // the search string is in SearchText Example:
        Usuals = _UsualsStore.Where(u => u.Contains(_SearchText.ToLower())).ToList();
    

    public void ProcessQuery()  /* TODO - search string is in SearchText */ 

    public void ProcessChoice()  /* TODO - search string is in SearchText */ 

【讨论】:

【参考方案3】:

如果你不介意使用non pure MVVM 方式。

MainPage.xaml

<AutoSuggestBox Name="SearchAutoSuggestBox"
        PlaceholderText="Search by keywords"
        QueryIcon="Find" QuerySubmitted="x:Bind ViewModel.SearchQuerySubmitted" IsEnabled="x:Bind ViewModel.CanExecuteSearchCommand, Mode=TwoWay"
        >
</AutoSuggestBox>

MainPageViewModel.cs

public class MainPageViewModel : INotifyPropertyChanged

    private bool _canExecuteSearchCommand;

    public MainPageViewModel()
    
        this.CanExecuteSearchCommand = true;
    

    public bool CanExecuteSearchCommand
    
        get  return _canExecuteSearchCommand; 
        set
        
            bool changed = _canExecuteSearchCommand != value;
            _canExecuteSearchCommand = value;

            if(changed)
                this.OnPropertyChanged();
        
    

    public void SearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
    
        // Just example disabling SearchBox
        this.CanExecuteSearchCommand = false;
    

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    

MainPage.cs

MainPageViewModel ViewModel = new MainPageViewModel();

【讨论】:

【参考方案4】:

UWP 绑定 Command/DelegateAutoSuggestBox in MVVM

对于 UWP 移动应用程序

创建一个 DelegateCommand 类

public class DelegateCommand<T> : ICommand

    private readonly Action<T> executeAction;
    Func<object, bool> canExecute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<T> executeAction)
        : this(executeAction, null)
    
        //var a = ((Page)(((Func<object, bool>)(executeAction.Target)).Target)).Name;
        //((ViewModel.VMBranchSelection)(executeAction.Target)).;

    

    public DelegateCommand(Action<T> executeAction, Func<object, bool> canExecute)
    
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    

    public bool CanExecute(object parameter)
    
        return canExecute == null ? true : canExecute(parameter);
    

    public void Execute(object parameter)
    
        executeAction((T)parameter);
    
    public void RaiseCanExecuteChanged()
    
        EventHandler handler = this.CanExecuteChanged;
        if (handler != null)
        
            handler(this, new EventArgs());
        
    

在视图模型中

    public ICommand SuggessionSelectCity_QuerySubmitted
    
        get  return new DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs>(this.SuggessionSelectCityQuerySubmitted); 
    

    private void     SuggessionSelectCityQuerySubmitted(AutoSuggestBoxQuerySubmittedEventArgs obj)
    
        if (obj.ChosenSuggestion != null)
        
            AutosuggestionTextBoxName.Text = ((ModelName)   (obj.ChosenSuggestion)).Model's Property name;
//or
AutosuggestionTextBoxName.Text =(obj.ChosenSuggestion).property name    
        
        else
        

        
    

在 XAML 代码中

<AutoSuggestBox Grid.Column="1" x:Name="SuggessionSelectCity"  
            PlaceholderText="Search by keywords" QueryIcon="Find"
            ItemsSource="Binding PApplicantCityList"

            HorizontalAlignment="Center" VerticalAlignment="Center" DisplayMemberPath="Description" Width="250" Height="45">

                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="TextChanged">
                        <Core:EventTriggerBehavior.Actions>
                            <Core:InvokeCommandAction Command="Binding SuggessionSelectCityTextChange"/>
                        </Core:EventTriggerBehavior.Actions>
                    </Core:EventTriggerBehavior>

                    <Core:EventTriggerBehavior EventName="QuerySubmitted">
                        <Core:EventTriggerBehavior.Actions>
                            <Core:InvokeCommandAction Command="Binding SuggessionSelectCity_QuerySubmitted"/>
                        </Core:EventTriggerBehavior.Actions>
                    </Core:EventTriggerBehavior>

                    <Core:EventTriggerBehavior EventName="SuggestionChosen">
                        <Core:EventTriggerBehavior.Actions>
                            <Core:InvokeCommandAction Command="Binding SuggessionSelectCitySuggestionChosen"/>
                        </Core:EventTriggerBehavior.Actions>
                    </Core:EventTriggerBehavior>


                </Interactivity:Interaction.Behaviors>
            </AutoSuggestBox>
        </Grid>

在视图模型中为 Autosuggestion TextBox Itemssource 创建一个列表

private ObservableCollection<ResultMasterModel> ApplicantCityList;
    public ObservableCollection<ResultMasterModel> PApplicantCityList
    
        get  return ApplicantCityList; 
        set  this.SetProperty(ref this.ApplicantCityList, value); 
    

在上面的列表中添加一些硬编码值

在模型文件夹中创建模型

public class ResultMasterModel
   
    public string Code  get; set; 
    public string Description  get; set; 

【讨论】:

以上是关于UWP 绑定到 MVVM 中的 AutoSuggestBox的主要内容,如果未能解决你的问题,请参考以下文章

win10 uwp MVVM入门

WPF 绑定密码

从代码绑定到 WinRT/UWP 中的自定义附加属性

将 Ui 事件绑定到 UWP 中的命令 [重复]

UWP NavigationView通过MVVM切换到另一个页面

Windows-10 UWP 将图像 url 绑定到 ListView 中的图像源