UWP:将ListView ItemTemplate MenuFlyOut事件绑定到ViewModel

时间:2018-08-29 05:45:07

标签: c# xaml listview mvvm uwp

我有一个现有的UWP应用程序来管理网站和帐户的密码,但是大约3年前写时,我对MVVM并不十分了解,因此所有事件处理程序都位于View的代码中,现在我正在尝试通过将此代码移至ViewModel来解决此问题并使其更符合MVVM。

我拥有的现有功能之一是每个ListView项上的弹出菜单,因此用户可以编辑/删除条目(并执行其他几个功能),但是因为我正在为ListView ItemTemplate数据模板定义DataType,现在将无法识别到我的Viewmodel中的Click事件处理程序的绑定。

如您所料,我在命名空间和页面数据上下文中都定义了ViewModel,如下所示:

    <Page ....
      xmlns:vm="using:PassPort.ViewModels"
      ...>

    <Page.DataContext>
        <vm:MainViewModel/>
    </Page.DataContext>

这是我的ListView,它是ItemTemplate和DataTemplate。在FlyOut的每个MenuFlyoutItem中,我试图告诉它在ViewModel中使用该处理程序,但是它无法解析'vm'-它显示弯曲的行并说“在'Account'类型中找不到属性'vm'” 。

    </ListView Name="lvwAccounts"  
               ItemsSource="{x:Bind vm.AccountsView}" 
               .....>
       <ListView.ItemTemplate>
        <DataTemplate x:DataType="model:Account">
            <Grid MinHeight="36" HorizontalAlignment="Left" RightTapped="AccountsList_RightTapped">

                <FlyoutBase.AttachedFlyout>
                    <MenuFlyout Placement="Bottom">
                        <MenuFlyoutItem x:Name="OpenWebsiteButton" Text="Open Website" Click="{x:Bind vm.FlyoutOpenWebsiteButton_Click}"/>
                        <MenuFlyoutItem x:Name="EditButton" Text="Edit Account" Click="{x:Bind vm.FlyoutEditButton_Click}"/>
                        <MenuFlyoutItem x:Name="AddButton" Text="Add Account" Click="{x:Bind vm. FlyoutAddButton_Click}"/>
                        <MenuFlyoutItem x:Name="DeleteButton" Text="Delete Account" Click="{x:Bind vm.FlyoutDeleteButton_Click}"/>
                    </MenuFlyout>
                </FlyoutBase.AttachedFlyout>

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Row="0" Grid.Column="0" Text="{x:Bind AccountName}"  Foreground="{StaticResource Light}"
                           VerticalAlignment="Center" HorizontalAlignment="Stretch"/>

                <TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Bind Category}"  Foreground="{StaticResource Light}"
                           VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" />

                <TextBlock Grid.Row="0" Grid.Column="2" Text="{x:Bind UserID}" Foreground="{StaticResource Light}"
                           VerticalAlignment="Center" HorizontalAlignment="Left"/>

                <TextBlock Grid.Row="0" Grid.Column="3" Text="{x:Bind Password}" Foreground="{StaticResource Light}"
                           VerticalAlignment="Center" HorizontalAlignment="Left" />

                <TextBlock Grid.Row="0" Grid.Column="4" Text="{x:Bind PasswordHint}" Foreground="{StaticResource Light}"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

代码“ vm”中的所有其他位置都可以正常解析,因此看来由于DataType的缘故,它无法/不会解析我的ViewModel引用。

我也尝试过使用'Click =“ {Binding vm。[event handler]”},但这没有区别-有人知道我可以解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

Microsoft在DataTemplate and x:Bind中说:

  

在DataTemplate内部(无论用作项目模板,内容模板还是标题模板),Path的值不会在页面的上下文中解释,而是在数据对象被模板化的上下文中解释。为了能够在编译时验证其绑定(并为其生成有效的代码),DataTemplate需要使用x:DataType声明其数据对象的类型。

要在DataTemplate中绑定ViewModel,您需要使用binding而不是x:bind这样的代码。

<ListView Name="lvwAccounts"  
          ItemsSource="{x:Bind vm.AccountsView}" >
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="model:Account">
                <FlyoutBase.AttachedFlyout>
                    <MenuFlyout Placement="Bottom">
                        <MenuFlyoutItem x:Name="OpenWebsiteButton" Text="Open Website" Command="{Binding ElementName=lvwAccounts,Path=DataContext.FlyoutOpenWebsite}"/>

                    </MenuFlyout>
                </FlyoutBase.AttachedFlyout>
        </DataTemplate>
    </ListView.ItemTemplate>      
</ListView>

但是UWP中的binding无法绑定方法,而binding仅可以绑定命令。您应该将方法更改为命令。

我在MenuFlyoutItem中找不到Command属性,我们可以使用Behavior将UI事件绑定到ViewModel中的命令,请参见:WPF Binding UI events to commands in ViewModel

请参阅:https://stackoverflow.com/a/40774956/6116637

Why can't I use {x:Bind {RelativeSource Self}} in a data template?