kosmakoff
kosmakoff

Reputation: 368

Get bound data from container control with UWP

I am writing this app where I use the NavigationView control, and I would like to not have static menu items in it, so I bind this control's MenuItemsSource property to list of menu item objects described with class like this:

public sealed class MenuItem
{
    public string Name { get; set; }
    // ...
}

I then template this data using DataTemplate:

<DataTemplate x:DataType="menu:MenuItem">
    <NavigationViewItem Content="{x:Bind Name}" />
</DataTemplate>

Finally, I would like to react to ItemInvoked events, e.g. for navigation. For that I need to get the MenuItem instance that was bound to this specific NavigationViewItem. Alas, in event args there is only the container control itself, not the data it was made from. The closest I was to reaching the desired functionality is when binding the DataContext property of NavigationViewItem to bound data, like this:

<DataTemplate x:DataType="menu:MenuItem">
    <NavigationViewItem Content="{x:Bind Name}" DataContext={x:Bind} />
</DataTemplate>

But it seems slightly wrong, although I cannot think of better solution. Could someone help me out?

Update: I found the method XamlBindingHelper.GetDataTemplateComponent which returns some dynamic object with properties, and one of them is exactly the data I am after. If it is present there, why aren't there any helper methods to reliably get it back?

Getting to the data bound to container

Upvotes: 1

Views: 314

Answers (2)

mm8
mm8

Reputation: 169420

Your MenuItemTemplate should not contain a NavigationViewItem container. Replace it with a TextBlock:

<NavigationView.MenuItemTemplate>
    <DataTemplate x:DataType="menu:MenuItem">
        <TextBlock Text="{x:Bind Name}" />
    </DataTemplate>
</NavigationView.MenuItemTemplate>

You could then easily get a reference to the MenuItem source of the clicked item in the event handler by casting the InvokedItem property of the NavigationViewItemInvokedEventArgs:

private void OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
    MenuItem menuItem = args.InvokedItem as MenuItem;
    //access any properties of the clicked MenuItem here, e.g.:
    string name = menuItem.Name;
}

Upvotes: 0

Roy Li - MSFT
Roy Li - MSFT

Reputation: 8681

But it seems slightly wrong, although I cannot think of better solution. Could someone help me out?

Actually, in the ItemInvoked event, you could get an InvokedItem object directly from the NavigationViewItemInvokedEventArgs. And the InvokedItem object is the data that you used to bind to the NavigationViewMenuItem.

For example,if I have NavigationViewMenuItem template a like this:

 <DataTemplate x:Key="NavigationViewMenuItem" x:DataType="local:TestMenuItem">
        <NavigationViewItem Content="{x:Bind ItemName}" />
    </DataTemplate>

And the TestMenuItem object like this:

public class TestMenuItem 
{
    public string ItemName { get; set; }
}

Then in the ItemInvoked event, I could get get the value of the ItemName property like this:

  private void NavigationView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
    {
        // directly get the item value
        var item = args.InvokedItem as string;

        switch (item) 
        {
            case "AAA":
                ContentFrame.Navigate(typeof(AAAPage));
                break;
            case "BBB":
                ContentFrame.Navigate(typeof(BBBPage));
                break;
            case "CCC":
                ContentFrame.Navigate(typeof(CCCPage));
                break;

        };
    }

Upvotes: 0

Related Questions