MenuItem.IsEnabled связан с тем, есть ли что-то выбранное в списке или нет, но он не обновляется
У меня есть MenuItem, который должен быть включен, только если что-то выбрано в ListBox. Я написал конвертер из объекта в bool, который возвращает false, если этот объект == ноль, и true в противном случае. Я привязал его к ListBox.SelectedItem с моим конвертером, но он не работает. Размещение точки останова в конвертере показывает, что он никогда не работает. Элемент MenuItem всегда включен независимо от того, что.
Вот код xaml ListBox и MenuItem
<ListBox Name="TestsListBox"
HorizontalAlignment="Left" Height="93" VerticalAlignment="Top" Width="128"
Margin="0,5,-1.723,0" ItemsSource="{Binding Path=Tests, Mode=OneWay}">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Click="removeTest"
IsEnabled="{Binding ElementName=TestsListBox, Mode=OneWay,
Path=SelectedItem, Converter={StaticResource ObjectToBool}}"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Здесь я покажу, как конвертер объявлен как ресурс окна
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:ClassesLib="clr-namespace:Laba1;assembly=ClassesLib"
xmlns:local="clr-namespace:WpfApplication"
Title="MainWindow" Height="450" Width="525">
<Window.Resources>
<local:ObjectToBoolConverter x:Key="ObjectToBool"/>
</Window.Resources>
А вот и конвертер класса
namespace WpfApplication
{
class ObjectToBoolConverter: IValueConverter
{
// Converts value to boolean. If value is null, returns false.
// Otherwise returns true
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (null == value)
{
return false;
}
return true;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("This is oneway converter, so ConvertBack is not supported");
}
}
}
3 ответа
Отсюда вы сможете выяснить, что причина, по которой привязка ElementName не работает, заключается в том, что ContextMenu не является частью визуального дерева, как другие элементы управления, и поэтому не может принимать участие в таких сценариях привязки. AFAIK, PopUps имеют свойство PlacementTarget, к которому вы можете привязать и выяснить, как его использовать.
Вот как я это решил:
ПОСМОТРЕТЬ:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:ObjectToBoolConverter x:Key="ObjectToBool"/>
<ContextMenu x:Key="contextMenu" DataContext="{Binding PlacementTarget.SelectedItem, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Remove" Click="removeTest"
IsEnabled="{Binding Path=., Converter={StaticResource ObjectToBool}}"/>
</ContextMenu>
</Window.Resources>
<Grid>
<ListBox Name="TestsListBox"
HorizontalAlignment="Left" Height="93" VerticalAlignment="Top" Width="128"
Margin="0,5,-1.723,0" ContextMenu="{StaticResource ResourceKey=contextMenu}">
</ListBox>
</Grid>
</Window>
Код позади
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
List<string> teste = new List<string>();
teste.Add("test1");
teste.Add("test3");
teste.Add("test2");
TestsListBox.ItemsSource = teste;
}
private void removeTest(object sender, RoutedEventArgs e)
{
}
}
}
Конвертер остался прежним.
С Уважением,
Похоже, свойство ElementName в Binding не делает то, что я думал. Также очень отстойно, что XAML просто игнорирует и ничего не делает с неверными параметрами Binding: вместо этого должно появиться сообщение об ошибке. Я добавил DataContext в свое ContextMenu, удалил ElementName, и теперь он работает. Вот как я изменил код:
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}" >
<MenuItem Header="Add" Click="addTest"/>
<MenuItem Header="Remove" Click="removeTest"
IsEnabled="{Binding Mode=OneWay,
Path=SelectedItem, Converter={StaticResource ObjectToBool}}"/>
</ContextMenu>
Комментарий Dtex о дубликате помог мне в этом, хотя я думал, что мог бы использовать ElementName вместо DataContext.