C# MenuItem.IsEnabled绑定到是否在列表框中选择了某些内容,但它不';t更新

C# MenuItem.IsEnabled绑定到是否在列表框中选择了某些内容,但它不';t更新,c#,wpf,xaml,listbox,ivalueconverter,C#,Wpf,Xaml,Listbox,Ivalueconverter,我有一个菜单项,只有在列表框中选择了某些内容时才应启用该菜单项。我编写了一个从object到bool的转换器,如果object==null,则返回false,否则返回true。我用转换器将它绑定到ListBox.SelectedItem,但它不起作用。在转换器中放置断点表明它从未运行。无论发生什么情况,菜单项始终显示为启用状态 下面是ListBox和MenuItem的xaml代码 <ListBox Name="TestsListBox" HorizontalAlignm

我有一个菜单项,只有在列表框中选择了某些内容时才应启用该菜单项。我编写了一个从object到bool的转换器,如果object==null,则返回false,否则返回true。我用转换器将它绑定到ListBox.SelectedItem,但它不起作用。在转换器中放置断点表明它从未运行。无论发生什么情况,菜单项始终显示为启用状态

下面是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>

我就是这样解决的:

视图:


代码隐藏

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

        }
    }
}
使用System.Collections.Generic;
使用System.Windows;
使用System.Windows.Documents;
命名空间WpfApplication2
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
this.DataContext=this;
List teste=新列表();
测试添加(“测试1”);
测试添加(“测试3”);
测试添加(“测试2”);
TestsListBox.ItemsSource=teste;
}
私有void removeTest(对象发送方,RoutedEventArgs e)
{
}
}
}
转换器保持不变


关于,

我就是这样解决的:

视图:


代码隐藏

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

        }
    }
}
使用System.Collections.Generic;
使用System.Windows;
使用System.Windows.Documents;
命名空间WpfApplication2
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
this.DataContext=this;
List teste=新列表();
测试添加(“测试1”);
测试添加(“测试3”);
测试添加(“测试2”);
TestsListBox.ItemsSource=teste;
}
私有void removeTest(对象发送方,RoutedEventArgs e)
{
}
}
}
转换器保持不变


在这方面,

看起来绑定的ElementName属性并不像我想象的那样。另外,XAML忽略了绑定的错误参数,并且对这些参数不做任何处理,这也非常糟糕:它应该引发一个错误。 我将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。

看起来绑定的ElementName属性并不像我想象的那样。另外,XAML忽略了绑定的错误参数,并且对这些参数不做任何处理,这也非常糟糕:它应该引发一个错误。 我将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。

从这里,您应该能够发现ElementName绑定不起作用的原因是ContextMenu不像其他控件那样是可视化树的一部分,因此不能参与此类绑定场景。好的,弹出窗口有一个PlacementTarget属性,您可以绑定到该属性并了解如何使用它。


从这里,您应该能够发现ElementName绑定不起作用的原因是ContextMenu不像其他控件那样是可视化树的一部分,因此不能参与此类绑定场景。好的,弹出窗口有一个PlacementTarget属性,您可以绑定到该属性并了解如何使用。

是否设置了datacontext?您还尝试过将菜单项绑定到命令并实现canExecute方法吗?My DataContext是在Window的构造函数中设置的,用于将整个窗口设置为My ViewModel,ListBox从中获取其项,但它与是否启用该项无关。我没有试过按你说的做,这是我第一次听说这种方法。我不确定“Click=“removeTest”与将其绑定到命令有何不同。使用mvvm模式时,最好的做法是将域(业务逻辑)与代码隐藏文件隔离。代码背后应该有尽可能少的逻辑来增加重用的灵活性。这些命令可以带来各种好处,例如,可以更容易地实现撤销模式。命令的另一个好处是,它使您能够预先检查条件,从而自动启用和禁用按钮。这有助于将条件逻辑与业务逻辑分离(换句话说,我只能在满足所有条件的情况下执行该方法)。我认为启用/禁用菜单项与业务逻辑无关。如果您有“单向”,则更新源时不会更新视图。是否设置了datacontext?您还尝试过将菜单项绑定到命令并实现canExecute方法吗?My DataContext是在Window的构造函数中设置的,用于将整个窗口设置为My ViewModel,ListBox从中获取其项,但它与是否启用该项无关。我没有试过按你说的做,这是我第一次听说这种方法。我不确定“Click=“removeTest”与将其绑定到命令有何不同。使用mvvm模式时,最好的做法是将域(业务逻辑)与代码隐藏文件隔离。代码背后应该有尽可能少的逻辑来增加重用的灵活性。这些命令可以带来各种好处,例如,可以更容易地实现撤销模式。命令的另一个好处是,它使您能够预先检查条件,从而自动启用
<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>