这个问题是关于两个毛伊岛控制区(SwitchListView)-我在同一个问题中询问它们,因为我expecting岁,两个控制区问题的根本原因是相同的.但完全有可能它们是不同的问题,只是有一些共同的症状.(CollectionView也有类似的问题,但其他混杂因素使其更难证明.)

我在MAUI应用程序中使用双向数据绑定:对数据的更改可以直接来自用户,也可以来自后台轮询任务,该任务判断规范数据是否已在其他地方更改.我面临的问题是,视图模型的更改不会传播到Switch.IsToggledListView.SelectedItem属性,尽管控件确实会引发事件,表明它们"注意到"了属性的更改.其他控件(例如LabelCheckbox)are在视觉上得到了更新,表明视图模型通知工作正常,UI本身基本正常.

Build environment: Visual Studio 2022 17.2.0 preview 2.1
App environment: Android, either emulator "Pixel 5 - API 30" or a real Pixel 6

下面是示例代码,但最基本的问题是,这是否是代码中的某个错误(我是否需要"告诉"控件出于某种原因进行self 更新?)或者可能是毛伊岛的一个虫子(在这种情况下,我应该报告它)?

Sample code

下面的示例代码可以直接添加到"File new project"毛伊岛应用程序中(名称为"MauiPlayground"以使用相同的名称空间),也可以全部添加到from my demo code repo.每个例子都是独立的——你可以只try 一个.(然后更新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;
    }
}

switch 示例代码

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);
        }
    }
}

点击"切换"按钮后模拟器的屏幕截图,该按钮将更新视图模型:

Demonstration of Switch issue

笔记:

  • 复选框(绑定到同一VM属性)已更新
  • 复选框旁边的标签(绑定到同一VM属性)已更新
  • 按钮下方的标签表示switch.IsToggled为真
  • 下面的标签表明Switch.Toggled事件已引发
  • Switch本身并没有改变可见状态

直接点击Switch控制按钮,切换它.

ListView示例代码

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);
        }
    }
}

点击"切换"按钮后模拟器的屏幕截图,该按钮将更新视图模型:

Demonstration of ListView issue

笔记:

  • 列表视图下的标签(绑定到同一VM属性)已更新
  • 按钮下方的标签表示listView.SelectedItem具有新值
  • 下面的标签表明ListView.ItemSelected事件已引发
  • ListView本身似乎有no个选定项目

有趣的是,列表视图does实际上改变了外观:在点击按钮之前,第一个项目被视觉 Select (橙色).从列表中 Select 一个项目会手动更新所有属性,但我们会看到橙色的所选项目.

推荐答案

Switch.IsToggledhas been fixed的版本是已知的,但在下一个RC发布之前(6.0.300-RC.1)将不可用.

我没有发现任何关于ListView期的报道问题,但我能够复制它.这似乎是由 for each 项目创建的默认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>

Csharp相关问答推荐

ß != ss与ICU进行不区分大小写的比较

属性getter和setter之间的空性不匹配?

实体核心框架--HasColumnType和HasPrecision有什么不同?

如何注销Microsoft帐户?

dotnet集合中内部数组的局部变量副本的用途是什么?'

此反射有什么问题.是否发送值转换委托?

如何在实体框架中添加包含列表?

C#普罗米修斯指标

CA1508:';NULL=>;TRUE;始终为';TRUE';.移除或重构条件(S)以避免死代码

如何将MemberInitExpression添加到绑定中其他Lambda MemberInitExpression

如果是,我怎么才能让这个加75,如果不是,我怎么才能减go 100?

具有类型识别的泛型方法

Postgres ENUM类型在第一次运行时对Dapper不可见

.NET Google Workspace API获取错误CS0266

C#无法将.csv列转换为用于JSON转换的列表

在.NET Maui中,Flyoutindow/Hamburger菜单可以在shell 之外实现吗?

具有嵌套属性的IGGroup

ASP.NET Core 8 Web API:如何添加版本控制?

当我在Git中暂存文件更改时,它们会消失

根据运行时值获取泛型类型的字典