ItemsControl中MultiBinding Converter未触发问题求助
问题:SelectedItem变更时无法触发SelectedItemConverter
SelectedItem值发生变更时,无法触发SelectedItemConverter。尝试过使用SetCurrentValue和InvalidateProperty方法,也调整了NotifyOnSourceUpdated、UpdateSourceTrigger以及Mode等属性,但均未解决问题。是否需要在父级XAML中添加相关配置?
父级XAML代码
<local:Menu SelectedItem="{Binding SelectedMenuItem}" OnSelect="{Binding OnSelectCommand}" Items="{Binding MenuItems}"/>
自定义Menu控件代码
控件XAML
<UserControl> <UserControl.Resources> <vm:MockMenuViewModel x:Key="DesignViewModel"/> <cv:SelectedItemConverter x:Key="SelectedItemConverter"/> </UserControl.Resources> <ItemsControl d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ItemsSource="{Binding Path=MenuItems, Mode=OneWay}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel></StackPanel> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate DataType="{x:Type MenuItem}"> <Button Content="{Binding Name}" Command="{Binding OnSelect, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding}"> <Button.IsEnabled> <MultiBinding Converter="{StaticResource SelectedItemConverter}" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" Mode="OneWay"> <Binding Path="SelectedItem" UpdateSourceTrigger="PropertyChanged" Mode="OneWay"/> <Binding Path="." Mode="OneWay"/> </MultiBinding> </Button.IsEnabled> </Button> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </UserControl>
控件C#代码
public partial class Menu : UserControl, INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; public Menu() { InitializeComponent(); } public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( "SelectedItem", typeof(MenuItem), typeof(Menu), new PropertyMetadata(null, OnSelectedItemChanged)); public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register( "Items", typeof(IEnumerable<MenuItem>), typeof(Menu), new FrameworkPropertyMetadata(null)); public static readonly DependencyProperty OnSelectProperty = DependencyProperty.Register( "OnSelect", typeof(ICommand), typeof(Menu), new PropertyMetadata(null, OnSelectChanged)); public MenuItem SelectedItem { get => (MenuItem)GetValue(SelectedItemProperty); set { SetValue(SelectedItemProperty, value); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Items))); } } public IEnumerable<MenuItem> Items { get => (IEnumerable<MenuItem>)GetValue(ItemsProperty); set => SetValue(ItemsProperty, value); } public ICommand OnSelect { get => (ICommand)GetValue(OnSelectProperty); set => SetValue(OnSelectProperty, value); } public static void OnSelectedItemChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs) { var menu = dependencyObject as Menu; if (menu == null) { return; } menu.InvalidateProperty(SelectedItemProperty); menu.InvalidateProperty(ItemsProperty); } public static void OnSelectChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs) { var menu = dependencyObject as Menu; if (menu == null) { return; } menu.SetCurrentValue(OnSelectProperty, eventArgs.NewValue); } }
解决方案
1. 修正MultiBinding中SelectedItem的绑定
DataTemplate的DataContext是单个MenuItem实例,直接绑定SelectedItem会找不到该属性,必须通过RelativeSource指向父级Menu控件:
<MultiBinding Converter="{StaticResource SelectedItemConverter}" NotifyOnSourceUpdated="True" NotifyOnTargetUpdated="True" Mode="OneWay"> <!-- 添加RelativeSource指向Menu控件 --> <Binding Path="SelectedItem" RelativeSource="{RelativeSource AncestorType=local:Menu}" Mode="OneWay"/> <Binding Path="." Mode="OneWay"/> </MultiBinding>
2. 修正ItemsControl的ItemsSource绑定
自定义Menu控件的数据源依赖属性是Items,而非MenuItems,需要绑定到控件自身的Items属性:
<ItemsControl d:DataContext="{Binding Source={StaticResource DesignViewModel}}" <!-- 修改为绑定自身的Items属性 --> ItemsSource="{Binding Path=Items, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=OneWay}">
3. 移除无效的属性通知代码
- 删除
SelectedItem属性setter中错误的PropertyChanged触发代码:public MenuItem SelectedItem { get => (MenuItem)GetValue(SelectedItemProperty); set { SetValue(SelectedItemProperty, value); // 移除这行错误的通知 // PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Items))); } } - 删除
OnSelectedItemChanged中无效的InvalidateProperty调用(会导致不必要的循环):public static void OnSelectedItemChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs) { var menu = dependencyObject as Menu; if (menu == null) return; // 移除以下两行无效代码 // menu.InvalidateProperty(SelectedItemProperty); // menu.InvalidateProperty(ItemsProperty); }
4. 可选:显式指定父级绑定的Mode
父级XAML中可显式指定SelectedItem的绑定Mode为TwoWay(确保双向同步):
<local:Menu SelectedItem="{Binding SelectedMenuItem, Mode=TwoWay}" OnSelect="{Binding OnSelectCommand}" Items="{Binding MenuItems}"/>
内容的提问来源于stack exchange,提问作者Józef Podlecki
相关产品推荐
相关产品推荐

