WinUI 3:RadioMenuFlyoutItem的IsChecked属性二次重选后绑定失效
我创建了一个测试项目,用于验证从ViewModel设置RadioMenuFlyoutItem选中状态的功能,已提交相关Bug,可下载示例项目复现问题。
XAML代码
<Window x:Class="Test_menu_radioitem.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Test_menu_radioitem" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <StackPanel x:Name="RootPanel" Orientation="Vertical"> <StackPanel.Resources> <local:EnumToBoolConverter x:Key="EnumToBoolConverter" /> </StackPanel.Resources> <DropDownButton HorizontalAlignment="Left" Margin="0 1"> <TextBlock Text="测试按钮"/> <DropDownButton.Flyout> <MenuFlyout x:Name="AvailabilityFlyout" Placement="Bottom"> <RadioMenuFlyoutItem GroupName="1" Text="活跃" Command="{Binding SetUserAvailabilityCommand}" IsChecked="{Binding Presence, Converter={StaticResource EnumToBoolConverter}, ConverterParameter='Active', Mode=OneWay}"> <RadioMenuFlyoutItem.CommandParameter> <local:ContactPresence>Active</local:ContactPresence> </RadioMenuFlyoutItem.CommandParameter> </RadioMenuFlyoutItem> <RadioMenuFlyoutItem GroupName="1" Text="请勿打扰" Command="{Binding SetUserAvailabilityCommand}" IsChecked="{Binding Presence, Converter={StaticResource EnumToBoolConverter}, ConverterParameter='DoNotDisturb', Mode=OneWay}"> <RadioMenuFlyoutItem.CommandParameter> <local:ContactPresence>DoNotDisturb</local:ContactPresence> </RadioMenuFlyoutItem.CommandParameter> </RadioMenuFlyoutItem> <RadioMenuFlyoutItem GroupName="1" Text="离开" Command="{Binding SetUserAvailabilityCommand}" IsChecked="{Binding Presence, Converter={StaticResource EnumToBoolConverter}, ConverterParameter='Away', Mode=OneWay}"> <RadioMenuFlyoutItem.CommandParameter> <local:ContactPresence>Away</local:ContactPresence> </RadioMenuFlyoutItem.CommandParameter> </RadioMenuFlyoutItem> <RadioMenuFlyoutItem GroupName="1" Text="离线" Command="{Binding SetUserAvailabilityCommand}" IsChecked="{Binding Presence, Converter={StaticResource EnumToBoolConverter}, ConverterParameter='Offline', Mode=OneWay}"> <RadioMenuFlyoutItem.CommandParameter> <local:ContactPresence>Offline</local:ContactPresence> </RadioMenuFlyoutItem.CommandParameter> </RadioMenuFlyoutItem> </MenuFlyout> </DropDownButton.Flyout> </DropDownButton> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button Click="myButton_Click_Active">活跃</Button> <Button Click="myButton_Click_DoNotDisturb">请勿打扰</Button> <Button Click="myButton_Click_Away">离开</Button> <Button Click="myButton_Click_Offline">离线</Button> </StackPanel> </StackPanel>
后台代码(简化版)
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Data; using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows.Input; namespace Test_menu_radioitem { /// <summary> /// 可独立使用或在Frame内导航的空白窗口。 /// </summary> public sealed partial class MainWindow { public MainWindow() { this.InitializeComponent(); RootPanel.DataContext = new ViewModel(); } private void myButton_Click_Active(object sender, RoutedEventArgs e) { ((ViewModel)RootPanel.DataContext).Presence = ContactPresence.Active; } private void myButton_Click_DoNotDisturb(object sender, RoutedEventArgs e) { ((ViewModel)RootPanel.DataContext).Presence = ContactPresence.DoNotDisturb; } private void myButton_Click_Away(object sender, RoutedEventArgs e) { ((ViewModel)RootPanel.DataContext).Presence = ContactPresence.Away; } private void myButton_Click_Offline(object sender, RoutedEventArgs e) { ((ViewModel)RootPanel.DataContext).Presence = ContactPresence.Offline; } } public enum ContactPresence { Active, Away, DoNotDisturb, Offline } public class EnumToBoolConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { if (value != null && value.GetType().IsEnum && parameter is string strParam) { if (Enum.TryParse(value.GetType(), strParam, out var enumParam)) { return Equals(enumParam, value); } } return DependencyProperty.UnsetValue; } public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException(); } public class ViewModel : INotifyPropertyChanged { private ContactPresence _presence; public ContactPresence Presence { get => _presence; set { _presence = value; OnPropertyChanged(); } } public ICommand SetUserAvailabilityCommand { get; } public ViewModel() { Presence = ContactPresence.Away; SetUserAvailabilityCommand = new RelayCommand(Execute); } private void Execute(object param) { var value = (ContactPresence)param; Presence = value; } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } } public class RelayCommand : ICommand { private readonly Action<Object> _execute; private readonly Func<bool> _canExecute; public event EventHandler CanExecuteChanged; public RelayCommand(Action<object> execute) : this(execute, null) { } public RelayCommand(Action<object> execute, Func<bool> canExecute) { if (execute == null) throw new ArgumentNullException("execute"); _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(); } public void Execute(object parameter) { _execute(parameter); } public void RaiseCanExecuteChanged() { var handler = CanExecuteChanged; if (handler != null) { handler(this, EventArgs.Empty); } } }
问题现象
首次设置选中项时功能正常,但再次切换选中项(例如从“活跃”切换到“离开”后),数据绑定会失效,无法正确更新RadioMenuFlyoutItem的选中状态。
复现步骤
- 启动测试项目
- 查看默认选中的菜单项
- 点击任意其他状态按钮(比如“活跃”)
- 确认菜单中的选中状态显示正确
- 点击任意其他状态按钮(比如“离线”)
- 确认菜单中的选中状态显示正确
- 点击任意其他状态按钮(比如“活跃”)
- 实际结果:“活跃”菜单项未被选中
- 预期结果:“活跃”菜单项被选中
预期结果
切换ViewModel中的Presence属性时,对应的RadioMenuFlyoutItem应始终正确显示选中状态,比如点击“活跃”按钮后,“活跃”菜单项应被选中。
内容的提问来源于stack exchange,提问作者Valerii Nozdrenkov
相关产品推荐
相关产品推荐

