繁体   English   中英

为什么 MAUI 中的 Switch 和 ListView 控件不使用 2 路绑定更新?

[英]Why do Switch and ListView controls in MAUI not update with 2-way binding?

这个问题是关于两个 MAUI 控件( SwitchListView ) - 我在同一个问题中询问它们,因为我期望两个控件的问题的根本原因是相同的。 完全有可能它们是不同的问题,只是有一些共同的症状。 CollectionView有类似的问题,但其他混淆因素使其演示变得更加棘手。)

我在我的 MAUI 应用程序中使用 2 路数据绑定:对数据的更改可以直接来自用户,也可以来自检查规范数据是否已在其他地方更改的后台轮询任务。 我面临的问题是,对视图 model 的更改不会在视觉上传播到Switch.IsToggledListView.SelectedItem属性,即使控件确实引发了表明它们已经“注意到”属性更改的事件。 其他控件(例如LabelCheckbox视觉上更新,表明视图 model 通知工作正常,并且 UI 本身总体上是健康的。

构建环境:Visual Studio 2022 17.2.0 预览版 2.1
应用环境:Android,模拟器“Pixel 5 - API 30”或真正的 Pixel 6

示例代码都在下面,但基本问题是这是否是我代码中某处的错误(我是否需要“告诉”控件出于某种原因更新自己?)或者可能是 MAUI 中的错误(在这种情况下我应该大概报告它)?

示例代码

下面的示例代码可以直接添加到“文件新项目”MAUI 应用程序(名称为“MauiPlayground”以使用相同的命名空间),也可以从我的演示代码仓库中获得。 每个示例都相互独立 - 您可以只尝试一个。 (然后更新App.cs以将MainPage设置为正确的示例。)

这两个示例都有一个非常简单的情况:一个双向绑定到视图模型的控件,以及一个更新视图模型属性的按钮(以模拟真实应用程序中的“数据已在其他地方修改”)。 在这两种情况下,控件在视觉上都保持不变。

请注意,我在这两种情况下都指定了{Binding..., Mode=TwoWay} ,即使这是这些属性的默认值,只是为了非常清楚这不是问题所在。

ViewModelBase代码由两个示例共享,并且只是一种提高INotifyPropertyChanged.PropertyChanged的便捷方式,无需任何额外的依赖项:

ViewModelBase.cs:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MauiPlayground;

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public bool SetProperty<T>(ref T field, T value, [CallerMemberName] string name = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
        {
            return false;
        }
        field = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        return true;
    }
}

切换示例代码

SwitchDemo.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiPlayground.SwitchDemo">
    <StackLayout>
        <Label Text="Switch binding demo" />
        <HorizontalStackLayout>
            <Switch x:Name="switchControl"
                    IsToggled="{Binding Toggled, Mode=TwoWay}"
                    Toggled="Toggled" />
            <CheckBox IsChecked="{Binding Toggled, Mode=TwoWay}" />
            <Label Text="{Binding Toggled}" />
        </HorizontalStackLayout>

        <Button Text="Toggle" Clicked="Toggle" />
        <Label x:Name="manualLabel1" Text="Value set in button click handler" />
        <Label x:Name="manualLabel2" Text="Value set in toggled handler" />
    </StackLayout>
</ContentPage>

SwitchDemo.cs

namespace MauiPlayground;

public partial class SwitchDemo : ContentPage
{
    public SwitchDemo()
    {
        InitializeComponent();
        BindingContext = new ViewModel();
    }

    private void Toggle(object sender, EventArgs e)
    {
        var vm = (ViewModel)BindingContext;
        vm.Toggled = !vm.Toggled;
        manualLabel1.Text = $"Set in click handler: {switchControl.IsToggled}";
    }

    private void Toggled(object sender, ToggledEventArgs e) =>
        manualLabel2.Text = $"Set in toggled handler: {switchControl.IsToggled}";

    private class ViewModel : ViewModelBase
    {
        private bool toggled;
        public bool Toggled
        {
            get => toggled;
            set => SetProperty(ref toggled, value);
        }
    }
}

单击“切换”按钮后模拟器的屏幕截图,该按钮更新了视图模型:

Switch 问题演示

笔记:

  • 复选框(绑定到相同的 VM 属性)已更新
  • 复选框(绑定到相同的 VM 属性)旁边的 label 已更新
  • 按钮下方的label表示switch.IsToggled为真
  • 下面的 label 表示Switch.Toggled事件已引发
  • Switch本身没有变化可见state

直接单击Switch控件会在视觉上切换它。

列表视图示例代码

ListViewDemo.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiPlayground.ListViewDemo">
    <StackLayout>
        <Label Text="ListView binding demo" />
        <ListView x:Name="listView" ItemsSource="{Binding Items}"
                  SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
                  VerticalOptions="Start"
                  ItemSelected="ItemSelected"/>
        <Label Text="{Binding SelectedItem}" />
        <Button Text="Toggle" Clicked="Toggle" />
        <Label x:Name="manualLabel1" Text="Text set in button click handler" />
        <Label x:Name="manualLabel2" Text="Text set in item selected handler" />
    </StackLayout>
</ContentPage>

ListViewDemo.cs

namespace MauiPlayground;

public partial class ListViewDemo : ContentPage
{
    public ListViewDemo()
    {
        InitializeComponent();
        BindingContext = new ViewModel();
    }

    private void Toggle(object sender, EventArgs e)
    {
        var vm = (ViewModel)BindingContext;
        vm.SelectedItem = vm.SelectedItem == "First" ? "Second" : "First";
        manualLabel1.Text = $"Set in click handler: {listView.SelectedItem}";
    }

    private void ItemSelected(object sender, EventArgs e) =>
        manualLabel2.Text = $"Set in item selected handler: {listView.SelectedItem}";

    private class ViewModel : ViewModelBase
    {
        public List<string> Items { get; } = new List<string> { "First", "Second" };

        private string selectedItem = "First";
        public string SelectedItem
        {
            get => selectedItem;
            set => SetProperty(ref selectedItem, value);
        }
    }
}

单击“切换”按钮后模拟器的屏幕截图,该按钮更新了视图模型:

ListView 问题演示

笔记:

  • 列表视图下方的 label(绑定到相同的 VM 属性)已更新
  • 按钮下方的 label 表示listView.SelectedItem有新值
  • 下面的 label 表示已经引发了ListView.ItemSelected事件
  • ListView本身似乎没有选定的项目

有趣的是,列表视图确实改变了外观:在单击按钮之前,第一个项目在视觉上被选中(橙色)。 从列表中选择一个项目手动更新所有属性,但我们不到橙色的选定项目。

Switch.IsToggled的问题是已知的并已修复,但在下一个 RC 发布 (6.0.300-rc.1) 之前将不可用。

我没有发现任何关于ListView问题的报告问题,但我能够重现它。 这似乎是由为每个项目创建的默认ViewCell引起的。 可以通过像这样指定自定义ListView.ItemTemplate来修复它:

<ListView x:Name="listView" ItemsSource="{Binding Items}"
        SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
        VerticalOptions="Start"
        ItemSelected="ItemSelected">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding}" />
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

这些都可能是当前发布的 MAUI 版本的错误。

这个错误是最近发布的,并且已经有一个针对 Switch 的修复程序来解决这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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