Search code examples
mvvmuwpautosuggesttemplate10flyout

Template 10 UWP How to bind to a autoSuggestBox inside a MenuFlyoutItem


I am using the MVVM pattern to bind the properties of the AutoSuggestBox in a ViewPage to my ViewModel. This works fine when I am inside a Grid or a stackPanel.

But once I put the AutoSuggestBox inside a MenuFlyout of a Button. I get the following Error at compile time

Error Object reference not set to an instance of an object.

Any guidance on how to bind the properties of AutoSuggestBox inside the MenuFlyoutItem??

Here is the code I am trying to compile.

<Button>
  <Button.Flyout>
    <MenuFlyoutItem >
          <MenuFlyoutItem.Template>
             <ControlTemplate TargetType="MenuFlyoutItem">
                 <AutoSuggestBox Header="What's your name?"
                  TextChanged="{x:Bind ViewModel.FilterUsuals}"
                  QuerySubmitted="{x:Bind ViewModel.ProcessQuery}"
                  SuggestionChosen="{x:Bind ViewModel.ProcessChoice}"
                  ItemsSource="{Binding Elements}"
                  Text="{x:Bind ViewModel.SearchText, Mode=TwoWay}"
                  QueryIcon="Find" />
            </ControlTemplate>
          </MenuFlyoutItem.Template>
    </MenuFlyoutItem>
</Button.Flyout>
</Button >

Solution

  • I believe your error is because you are using a ControlTemplate that immediately changes the data context from the page, making your ViewModel out of scope. More importantly is that x:Bind is not supported in ControlTemplates. This means you can't use the handy x:Bind to Events and will need to create commands. You will have to use behaviors to accomplish this most easily.

    Something similar to this.

    <AutoSuggestBox>
       <interactivity:Interaction.Behaviors>
          <core:EventTriggerBehavior EventName="TextChanged">
             <core:InvokeCommandAction Command="{Binding TextChangedCommand}" />
          </core:EventTriggerBehavior>
       </interactivity:Interaction.Behaviors>
    </AutoSuggestBox>
    

    Or similar to this.

    public class AutoSuggestBoxAttachedProperties : Windows.UI.Xaml.DependencyObject
    {
        public static ICommand GetTextChangedCommand(Windows.UI.Xaml.Controls.AutoSuggestBox obj)
            => (ICommand)obj.GetValue(TextChangedCommandProperty);
        public static void SetTextChangedCommand(Windows.UI.Xaml.Controls.AutoSuggestBox obj, ICommand value)
            => obj.SetValue(TextChangedCommandProperty, value);
        public static readonly DependencyProperty TextChangedCommandProperty =
            DependencyProperty.RegisterAttached("TextChangedCommand", typeof(ICommand),
                typeof(AutoSuggestBoxAttachedProperties), new PropertyMetadata(null, TextChangedCommandChanged));
    
        public static object GetTextChangedCommandParameter(Windows.UI.Xaml.Controls.AutoSuggestBox obj)
            => (object)obj.GetValue(TextChangedCommandParameterProperty);
        public static void SetTextChangedCommandParameter(Windows.UI.Xaml.Controls.AutoSuggestBox obj, object value)
            => obj.SetValue(TextChangedCommandParameterProperty, value);
        public static readonly DependencyProperty TextChangedCommandParameterProperty =
            DependencyProperty.RegisterAttached("TextChangedCommandParameter", typeof(object),
                typeof(AutoSuggestBoxAttachedProperties), new PropertyMetadata(null));
    
        private static void TextChangedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var box = d as Windows.UI.Xaml.Controls.AutoSuggestBox;
            box.TextChanged -= Box_TextChanged;
            if (e.NewValue != null)
            {
                box.TextChanged += Box_TextChanged;
            }
        }
    
        private static void Box_TextChanged(Windows.UI.Xaml.Controls.AutoSuggestBox sender, Windows.UI.Xaml.Controls.AutoSuggestBoxTextChangedEventArgs args)
        {
            var command = GetTextChangedCommand(sender);
            if (command != null)
            {
                var parameter = GetTextChangedCommandParameter(sender);
                command.Execute(parameter);
            }
        }
    }
    

    Then this.

    <AutoSuggestBox 
        ex:AutoSuggestBoxAttachedProperties.TextChangedCommand="{Binding TextChangedCommand}" />
    

    Best of luck. /Jerry