【问题标题】:MAUI BindingContext does not work when set to a BindingMAUI BindingContext 在设置为 Binding 时不起作用
【发布时间】:2022-10-15 01:34:25
【问题描述】:

在我的主页上,我有一个包含一些属性的 MainViewModel,其中一个是 EffectsCtrl(另一个视图模型,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 中找不到效果“成员”,并且在启动构建时失败并出现错误“绑定:在“效果”上找不到属性“效果”。 ViewModel.MainViewModel"'。 在这一点上,我有点困惑和好奇,所以我尝试了其他一些组合,比如

<ListView
  BindingContext={Binding EffectsCtrl}
  ItemsSource="{Binding EffectsCtrl.Effects}"
  HasUnevenRows="True"
  VerticalOptions="FillAndExpand">
  ...
</ListView>

这可以正常编译,没有来自 IDE 的警告或构建错误,但列表根本不显示 - 我认为是由于绑定错误,因为我在调试器中检查了 EffectsCtrl,一切都很好,元素像往常一样添加到列表中。调试器也没有显示警告或错误。

这让我想到了我的问题:这是一个错误还是我对绑定有误解?当我进行第一次更改时,我假设当我更改 ListView 的 BindingContext 时,它会影响其 ItemsSource 字段上的绑定。而且我更加困惑,因为第三种情况似乎在一定程度上证实了我的假设。那么有人可以确认这是一个错误或向我解释为什么第二种情况无效吗?

编辑: 我做了一些更多的测试,当 ContentPage 声明中的x:DataType="vm:MainViewModel" 被删除时,第二种情况按预期工作。这是为什么?

【问题讨论】:

  • BindingContext 不行,你先做的就是正确的方法,不要改
  • @FreakyAli您能否更详细地解释一下为什么第一种方法是正确的,为什么它不能那样工作或它是如何工作的?或者我在哪里可以找到我的问题的答案?因为官方文档(数据绑定基础和 MVVM)提供的信息很少。
  • 可以将 BindingContext 视为一个将您的模型保存为实际数据以及您的命令和东西的类,现在绑定充当一对一映射,因此您需要将相同类型的属性绑定到相同类型的控件属性。因此,假设您将 View(Page) 与 ViewModel(BindingContext) 绑定,它基本上将此映射分配给其子级,因此假设您的此 Page 有一个 ContentView 并且您的 ViewModel 中有一个对象如果您想将一个对象分配给另一个反对你会怎么做?你会做类似 MyListSource = ViewModel.ItemSource 对吗?
  • 现在,如果您想将上面的 Object 映射转换为 Binding,您可以执行以下操作。 MyListSource= "{Binding ViewModel.Itemsource}"希望这对你有帮助:)
  • @FreakyAli 感谢您提供更详细的解释,但我认为情况并非如此。 EffectsCtrl 本身就是一个 ViewModel(可能名称具有误导性),它存储在 MainViewModel 中,它包含绑定到 ListView.ItemsSource 的 Effects ObservableCollection。但是因为它被用作 MainViewModel 的属性,所以我无法使用 RelativeSource AncestorType 直接从 ListView.DataTemplate 引用它。这就是为什么我想将 EffectsCtrl 绑定到 ListView.BindingContext 和 Effects 而不是 EffectsCtrl.Effects 绑定到 ItemsSource。

标签: listview data-binding maui


【解决方案1】:

Data binding basics / view-to-view bindings。将x:Reference 用于元素的x:Name

如果您的 EffectsCtrl 具有 x:Name myEffectsCtrl,则执行以下操作:

<EffectsCtrl x:Name="myEffectsCtrl" ... />
<ListView
  BindingContext="{x:Reference myEffectsCtrl}" ... />

【讨论】:

【解决方案2】:

我自己在Compiled bindings 文档中找到了答案。事实证明x:DataType="vm:MainViewModel" 是问题所在,尽管这种行为是绝对正确的,问题是由于我的误解造成的。在ContentPage 上设置的此属性会导致编译绑定。正如上述文件所述

将 VisualElement 上的 x:DataType 属性设置为 VisualElement 及其子项将绑定到的对象的类型。

这意味着 ContentPage 中的每个元素都应该将 BindingContext 设置为 MainViewModel 的一个实例(除非另一个 x:DataType 属性另有说明,我假设)。因此,当在第二种情况下使用绑定到 Effects 时,即使 BindingContext 设置为 EffectsCtrl,编译器也会抛出错误 - 它假定 BindingContext 将是 MainViewModel 的实例(而不是 EffectsControl 实例)并且它确实不包含Effects 属性。

我为此提供了两种可能的解决方案:

第一种解决方案:

只需通过从ContentPage 属性中删除x:DataType="vm:MainViewModel" 来切换到运行时验证。但是这样的操作会产生一些负面后果 - 您会丢失编译时绑定验证,运行时验证会影响性能,并且 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 通过依赖注入传递,一切正常。

第二种解决方案:

为了保留已编译的绑定,我刚刚将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>

我发现这种行为不是很直观,但现在我理解了这个概念,我认为这个问题有点傻。无论如何,我希望这可以帮助像我这样迷失的初学者。

【讨论】:

    猜你喜欢
    • 2017-09-19
    • 2014-10-22
    • 1970-01-01
    • 2022-01-22
    • 2020-06-29
    • 2022-08-23
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多