简体   繁体   中英

x:Bind ViewModel RelayCommand to a command inside DataTemplate

I'm trying to bind a IAsyncRelayCommand (MVVM Toolkit) from my view model using x:Bind within a DataTemplate.

This is my view model:

public class BuildingViewModel : ObservableObject
{
    public ObservableCollection<ObservableProjectItem> ProjectItems { get; } = new ObservableCollection<ObservableProjectItem>();

    public IAsyncRelayCommand AddProjectItemCommand { get; }

    public BuildingViewModel()
    {
        AddProjectItemCommand = new AsyncRelayCommand<ContentDialog>(async (dialog) => await AddProjectItem(dialog));
    }

    private async Task AddProjectItem(ContentDialog dialog)
    {
        // Do something
    }
}

And this my view (XAML):

<TreeView ItemsSource="{x:Bind ViewModel.ProjectItems}">
    <TreeView.ItemTemplate>
        <DataTemplate x:DataType="model:ObservableProjectItem">
            <TreeViewItem ItemsSource="{x:Bind Children}">
                <TextBlock Text="{x:Bind Name}" />
                <TreeViewItem.ContextFlyout>
                    <MenuFlyout>
                        <MenuFlyoutItem Command="{HERE I WANT BIND THE COMMAND}" />
                        <MenuFlyoutItem Text="Löschen" Icon="Delete" />
                    </MenuFlyout>
                </TreeViewItem.ContextFlyout>
            </TreeViewItem>
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

The view have the following code behind:

public sealed partial class BuildingView : Page
{
    public BuildingView()
    {
        this.InitializeComponent();
    }

    internal BuildingViewModel ViewModel = Ioc.Default.GetService<BuildingViewModel>();
}

My problem is {x:Bind ViewModel.AddProjectItemCommand} doesn't work. Within the DataTemplate the x:Bind scope is ObservableProjectItem . How can I navigate to my root ViewModel respectively bind my command declared in the view model?

Unfortunately, these kind of operations are not well supported by x:Bind (see this WinUI issue for more context). You could however use Binding to solve that problem. For this, you need to set x:Name on your page and use the ElementName property:

<Page x:Name="MyPage">
    <TreeView ItemsSource="{x:Bind ViewModel.ProjectItems}">
        <TreeView.ItemTemplate>
            <DataTemplate x:DataType="model:ObservableProjectItem">
                <TreeViewItem ItemsSource="{x:Bind Children}">
                    <TextBlock Text="{x:Bind Name}" />
                    <TreeViewItem.ContextFlyout>
                        <MenuFlyout>
                            <MenuFlyoutItem Command="{Binding Path=AddProjectItemCommand, ElementName=MyPage}" />
                            <MenuFlyoutItem Text="Löschen" Icon="Delete" />
                        </MenuFlyout>
                    </TreeViewItem.ContextFlyout>
                </TreeViewItem>
            </DataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Page>

I have also encountered this problem. My solution is this:

  • declare ICommand in ViewModel as static
  • use a construct {x:Bind Path=...}

Something like:

In ViewModel:

static public ICommand Command_TapColorSet { get; set; }

in XAML:

xmlns:models="using:TestProj.Models"
xmlns:viewmodels="using:TestProj.ViewModels"

<ItemsControl.ItemTemplate>
    <DataTemplate x:DataType="models:ColorsSet">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Interactivity:Interaction.Behaviors>
                <Core:EventTriggerBehavior EventName="Tapped">
                    <Core:InvokeCommandAction Command="{x:Bind Path=viewmodels:OptionsViewModel.Command_TapColorSet}" CommandParameter="{Binding}" />
                </Core:EventTriggerBehavior>
            </Interactivity:Interaction.Behaviors>.
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>

I realise that static ICommand looks a bit strange, but at least this approach works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM