当前位置: 首页 > 知识库问答 >
问题:

为什么MAUI中的Switch和ListView控件不使用双向绑定进行更新?

武博艺
2023-03-14

这个问题是关于两个MAUI控件(开关列表视图)-我在同一个问题中询问这两个控件,因为我希望这两个控件的问题根源是相同的。但完全有可能它们是不同的问题,只是有一些共同的症状。(CollectionView也有类似的问题,但其他混杂因素使演示变得更加困难。)

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

构建环境:Visual Studio2022 17.2.0预览版2.1
应用程序环境:Android,模拟器像素5-API 30或真正的像素6

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

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

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

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

ViewModelBase代码由两个示例共享,它只是一种方便的方式,可以引发INotifyPropertyChanged。PropertyChanged没有任何额外的依赖项:

ViewModelBase。反恐精英:

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

开关emo.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>

切换演示。反恐精英

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

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

注意事项:

  • 复选框(绑定到同一VM属性)已更新

直接单击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。反恐精英

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

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

注意事项:

  • 列表视图下方的标签(绑定到同一VM属性)已更新
  • 按钮下方的标签表示<代码>列表视图。SelectedItem具有新值
  • 下面的标签表示<代码>列表视图。ItemSelected事件已引发
  • 列表视图本身似乎没有选定的项目

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

共有2个答案

邹俊豪
2023-03-14

这两个可能都是毛伊岛目前发布的版本中的漏洞。

此错误最近发布,交换机已经有了解决此问题的修复程序。

蒋高杰
2023-03-14

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

我没有发现任何有关ListView问题的报告问题,但我能够重现它。这似乎是由为每个项目创建的默认ViewCell造成的。可以通过指定自定义的列表视图来修复它。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>
 类似资料:
  • 问题内容: 我有一个简单的Bean,它具有彼此相关的某些属性。例如,此bean具有一个名为 discountRate 的属性和另一个名为 DiscountValue 的属性。DiscountRate是应用于销售的折扣百分比(%)。discountValue是应用于销售的折扣值($)。由于用户可以告知百分比或值,而且我需要将两个值存储在数据库中,因此JavaFX双向绑定可以解决此问题,但是,正如您可

  • 初始值设置为true后,我与切换按钮的双向绑定将被分离。当我取消按钮时,它不再绑定。 我有两个切换按钮: 我希望绑定到的BackupViewModel(实例为BackupVM)中的我的属性: 当一个被切换时,我会显示一个特定的用户控件(视图)并隐藏另一个。我需要做的是告诉我的底层视图模型视图是隐藏的,这样我就可以停止刷新一些数据的计时器。加载IsChecked值后,由于某种原因绑定会被分离。以下是

  • 本文向大家介绍什么是双向绑定?原理是什么?相关面试题,主要包含被问及什么是双向绑定?原理是什么?时的应答技巧和注意事项,需要的朋友参考一下 双向数据绑定个人理解就是存在data→view,view→data两条数据流的模式。其实可以简单的理解为change和bind的结合。目前双向数据绑定都是基于Object.defineProperty()重新定义get和set方法实现的。修改触发set方法赋值

  • 问题内容: 给一个非常基础的类(将导入解析为javafx包): 某些字段表示在.fxml文件中定义的控件: 以及最基本使用属性包装器的数据模型: 我尝试将ui控件与Initialize中的数据模型绑定: 但是这样做, 我得到了不可编辑的控件 。注释掉Bindings.bindBidirectional行后,该控件通常可以编辑,并且可以通过text01字段访问其值。 此装订单中缺少的成分是什么? 问

  • Mpx针对表单组件提供了wx:model双向绑定指令,类似于v-model,该指令是一个语法糖指令,监听了组件抛出的输入事件并对绑定的数据进行更新,默认情况下会监听表单组件的input事件,并将event.detail.value中的数据更新到组件的value属性上。 简单实用示例如下: <view> <input type="text" wx:model="{{message}}"> <

  • 双向绑定这个概念在angular出现的时候,就作为王牌概念. 现在几乎是个js前端框架,就有这个功能. 它的概念是: 某个变量, 如果展现在页面上的话: 如果在代码层面进行修改, 那么页面的值就会发生变化 如果在页面进行修改(例如在input标签中), 那么代码的值就会发生变化. 一个演示例子. 在我们的项目中,增加一个 vue页面: src/components/TwoWayBinding.vu