這個問題是關于兩個 MAUI 控制元件(Switch和ListView) - 我在同一個問題中詢問它們,因為我期望兩個控制元件的問題的根本原因是相同的。完全有可能它們是不同的問題,只是有一些共同的癥狀。(CollectionView有類似的問題,但其他混淆因素使演示變得更加棘手。)
我在我的 MAUI 應用程式中使用 2 路資料系結:對資料的更改可以直接來自用戶,也可以來自檢查規范資料是否已在其他地方更改的后臺輪詢任務。我面臨的問題是視圖模型的更改不會在視覺上傳播到Switch.IsToggledandListView.SelectedItem屬性,即使控制元件確實引發了表明它們已經“注意到”屬性更改的事件。其他控制元件(例如Label和Checkbox)在視覺上更新,表明視圖模型通知作業正常并且 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);
}
}
}
單擊“切換”按鈕后模擬器的螢屏截圖,該按鈕更新了視圖模型:

筆記:
- 復選框(系結到相同的 VM 屬性)已更新
- The label next to the checkbox (bound to the same VM property) has updated
- The label below the button indicates that
switch.IsToggledis true - The label below that indicates that the
Switch.Toggledevent has been raised - The
Switchitself has not changed visible state
Clicking on the Switch control directly does visually toggle it.
ListView sample code
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);
}
}
}
Screenshot of the emulator after clicking on the "Toggle" button, which updates the view-model:

Notes:
- The label below the list view (bound to the same VM property) has updated
- The label below the button indicates that
listView.SelectedItemhas the new value - The label below that indicates that the
ListView.ItemSelectedevent has been raised - The
ListViewitself appears to have no selected item
Interestingly, the list view does actually change appearance: before clicking on the button, the first item is visually selected (in orange). Selecting an item from the list manually updates all the properties, but we don't see the selected item in orange.
uj5u.com熱心網友回復:
已知問題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>
uj5u.com熱心網友回復:
這些都可能是當前發布的 MAUI 版本的錯誤。
這個錯誤是最近發布的,并且已經有一個針對 Switch 的修復程式來解決這個問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/457631.html
標籤:c# data-binding maui
