简体   繁体   English

MenuItem.IsEnabled绑定到列表框中是否选择了某些内容,但不会更新

[英]MenuItem.IsEnabled is bound to whether there is something selected in Listbox or not, but it doesn't update

I have a MenuItem, which should be enabled only if there is something selected in ListBox. 我有一个MenuItem,只有在ListBox中选择了某些东西时才应启用它。 I wrote a converter from object to bool, which returns false, if that object == null, and true otherwise. 我编写了一个从对象到布尔的转换器,如果该对象== null,则返回false,否则返回true。 I bound it to ListBox.SelectedItem with my converter, but it doesn't work. 我用转换器将其绑定到ListBox.SelectedItem,但是它不起作用。 Placing a breakpoint in the converter shows, that it never runs. 在转换器中放置一个断点表明它永远不会运行。 The MenuItem appears always enabled no matter what. 无论如何,菜单项始终显示为启用状态。

Here is xaml code of the ListBox and of MenuItem 这是ListBox和MenuItem的xaml代码

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

Here I show how converter is declared as window's resource 在这里,我展示了如何将转换器声明为窗口的资源

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

And here is the converter class 这是转换器类

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

RelativeSource and Popup RelativeSource和弹出窗口

From here you should be able to find out that the reason ElementName binding doesn't work is because the ContextMenu isn't part of the visual tree as other controls are, and therefore can not take part in such binding scenarios. 从这里您应该能够发现ElementName绑定不起作用的原因是因为ContextMenu不像其他控件那样属于可视化树的一部分,因此不能参与此类绑定方案。 AFAIK, PopUps have a PlacementTarget property that you can bind to and figure out how to use. AFAIK,PopUps具有一个PlacementTarget属性,您可以将其绑定并确定如何使用。

This was how I solved it: 这就是我解决的方法:

VIEW: 视图:

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

CODE BEHIND 后面的代码

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)
        {

        }
    }
}

The converter stayed the same. 转换器保持不变。

Regards, 问候,

Looks like ElementName property of Binding doesn't do what I thought it does. 看起来Binding的ElementName属性没有执行我认为的操作。 Also it sucks very much that XAML just ignores and does nothing about incorrect parameters of Binding: it should raise an error instead. XAML只会忽略它,而且对Binding的不正确参数也不做任何事情:它应该引发错误。 I added DataContext to my ContextMenu, removed ElementName, and it is working now. 我将DataContext添加到我的ContextMenu中,删除了ElementName,并且现在可以正常工作。 This is how I changed the code: 这就是我更改代码的方式:

<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's comment about a duplicate helped me with this, even though I thought I could use ElementName instead of DataContext. 即使我认为可以使用ElementName代替DataContext,Dtex对重复项的评论也帮助了我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM