在我的主页上,我有一个 MainViewModel,其中包含一些属性,其中一个是 EffectsCtrl(另一个 View 模型,EffectsControl 类的实例),它包含一些与管理效果列表相关的逻辑。为了显示此列表,我的主页上有以下 ListView:
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Effects"
x:Class="Effects.MainPage"
xmlns:vm="clr-namespace:Effects.ViewModel"
x:DataType="vm:MainViewModel">
...
<ListView
ItemsSource="{Binding EffectsCtrl.Effects}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
</ContentPage>
以上工作正常 - 列表正确显示并更新更改。
但在某个时候我把它改成了这样
<ListView
BindingContext={Binding EffectsCtrl}
ItemsSource="{Binding Effects}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand">
...
</ListView>
令我惊讶的是,我的 IDE (Visual Studio) 向我显示了一个提示:效果“在数据上下文 MainViewModel 中找不到成员”,并且在启动构建时失败并出现错误“绑定(bind):未找到属性“效果”” “Effects.ViewModel.MainViewModel”'。 此时我有点困惑和好奇,所以我尝试了一些其他组合,例如
<ListView
BindingContext={Binding EffectsCtrl}
ItemsSource="{Binding EffectsCtrl.Effects}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand">
...
</ListView>
并且编译正常,没有来自 IDE 的警告或构建错误,但列表根本不显示 - 我认为是由于错误的绑定(bind),因为我在调试器中检查了 EffectsCtrl,一切都很好,并且元素像往常一样添加到列表中。调试器也没有显示任何警告或错误。
这让我想到了我的问题:这是一个错误还是我误解了绑定(bind)?当我进行第一次更改时,我假设当我更改 ListView 的 BindingContext 时,它将影响其 ItemsSource 字段上的绑定(bind)。我更困惑了,因为第三个案例似乎在某种程度上证实了我的假设。那么有人可以确认这是一个错误或向我提供解释为什么第二种情况无效吗?
编辑:
我做了更多测试,当 x:DataType="vm:MainViewModel"
从 ContentPage 声明中删除,第二种情况按预期工作。这是为什么?
最佳答案
我自己在 Compiled bindings 中找到了答案文档。事实证明, x:DataType="vm:MainViewModel"
是问题所在,尽管这种行为绝对正确,并且问题是由于我的误解造成的。 ContentPage
上设置的此属性会导致绑定(bind)的编译。正如上述文档所述
Set an x:DataType attribute on a VisualElement to the type of the object that the VisualElement and its children will bind to.
这意味着 ContentPage
中的每个元素都应将 BindingContext
设置为 MainViewModel 的实例(除非另一个 x:DataType
属性另有说法,我想)。因此,当在第二种情况下使用绑定(bind)到 Effects
时,即使 BindingContext
设置为 EffectsCtrl,编译器也会抛出错误 - 它假定 BindingContext
> 将是 MainViewModel 的实例(而不是 EffectsControl 实例),并且它确实不包含 Effects
属性。
我对此提出了两种可能的解决方案:
第一个解决方案:
只需从 ContentPage
属性中删除 x:DataType="vm:MainViewModel"
即可切换到运行时验证。但这样的操作会产生一些负面后果 - 您会失去编译时绑定(bind)验证,运行时验证会影响性能,并且 IDE 不会提供自动完成功能(至少 Visual Studio 是这样)。
代码如下所示:
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Effects"
x:Class="Effects.MainPage"
xmlns:vm="clr-namespace:Effects.ViewModel">
...
<ListView
BindingContext="{Binding EffectsCtrl}"
ItemsSource="{Binding Effects}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
</ContentPage>
MainViewModel 通过依赖注入(inject)传递,一切正常。
第二个解决方案:
为了保留已编译的绑定(bind),我刚刚将 x:DataType="vm:EffectsControl"
属性添加到 ListView
中,但随后我无法使用 BindingContext="{Binding EffectsCtrl}"
属性,因为 EffectsCtrl 本身没有 EffectsCtrl 属性。因此,我将 ListView
包装在一个新的 ContentView
类中,如下所示:
<ContentView
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Effects.EffectsListView"
xmlns:vm="clr-namespace:Effects.ViewModel"
x:DataType="vm:EffectsControl">
<ListView
ItemsSource="{Binding Effects}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
</ContentView>
并用新类替换了主页上的列表
<ContentPage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Effects"
x:Class="Effects.MainPage"
xmlns:vm="clr-namespace:Effects.ViewModel"
x:DataType="vm:MainViewModel">
...
<local:EffectsListView BindingContext="{Binding EffectsCtrl}"/>
</ContentPage>
我发现这种行为不是很直观,但现在当我理解这个概念时,我认为这个问题有点愚蠢。不管怎样,我希望这能帮助像我这样迷茫的初学者。
关于listview - 设置为 Binding 时,MAUI BindingContext 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74046975/