我有一个现有的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]”},但这没有区别-有人知道我可以解决这个问题吗?
答案 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?