无法为键绑定提供绑定

Unable to provide a binding for a Keybinding

我有一个包含 Dev Express 网格控件的 UserControl,我正在尝试连接一个命令来处理当用户在选定行时按下删除键的情况。

我的第一次迭代是:

<dxg:GridControl.InputBindings>
    <KeyBinding Key="Delete" Command="{Binding DataContext.DeleteItemCommand}"/>
</dxg:GridControl.InputBindings>

在运行时使用 Snoop 检查结果时,我看到了这个绑定错误: System.Windows.Data Error:2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=DataContext.DeleteItemCommand; DataItem=null; target element is 'KeyBinding' (HashCode=39502614); target property is'Command' (type 'ICommand')

在做了一些研究后,我发现有几篇文章说他们可以通过添加相对来源来实现这一点,所以我改变了我的绑定:

<dxg:GridControl.InputBindings>
    <KeyBinding Key="Delete" Command="{Binding DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=views:MyUserControl}}"/>
</dxg:GridControl.InputBindings>

现在在运行时我看到了这个错误: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='MyProject.Views.MyUserControl', AncestorLevel='1''. BindingExpression:Path=DataContext.DeleteItemCommand; DataItem=null; target element is 'KeyBinding' (HashCode=35267081); target property is 'Command' (type 'ICommand')

在我做的研究中,我注意到此功能已添加到 .NET 4.0 中,但我使用的是 .NET 4.5,所以这应该不是问题。

我还注意到所有示例都在 window 级别指定了 InputBindings,因此在我的应用程序中执行相同的操作是不可行的,我确实尝试移动绑定达到用户控制级别,但收到相同的结果。

也不确定它是否重要,但我的用户控件也继承了自定义基 class,因此我无法尝试使用命名元素。

请尝试对包含 DeleteItemCommand 命令定义的 DataContext 使用代理,并使用该代理访问您需要的命令。我认为您无法访问该命令并出现 BindingExpression 错误的原因是您与 DataGrid 对象不在同一逻辑树中。这里有几点我认为可以帮助您解决问题。

代理 class:

public class FreezableProxyClass : Freezable
{
    protected override Freezable CreateInstanceCore()
    {
        return new FreezableProxyClass();
    }


    public static readonly DependencyProperty ProxiedDataContextProperty = DependencyProperty.Register(
        "ProxiedDataContext", typeof (object), typeof (FreezableProxyClass), new PropertyMetadata(default(object)));

    public object ProxiedDataContext
    {
        get { return (object) GetValue(ProxiedDataContextProperty); }
        set { SetValue(ProxiedDataContextProperty, value); }
    }
}

Proxy class xaml 声明(这是具有您需要的 DataContext 的控件的名称):

 <UserControl.Resources>
        <dataGridSoHelpAttempt:FreezableProxyClass x:Key="ProxyElement" ProxiedDataContext="{Binding Source={x:Reference This}, Path=DataContext}"/>
    </UserControl.Resources>

代理 Class 使用

 <dxg:GridControl.InputBindings>
            <KeyBinding Key="Delete" Command="{Binding Source={StaticResource ProxyElement}, 
                Path=ProxiedDataContext.DeleteItemCommand}"/>
        </dxg:GridControl.InputBindings>

更新

<Window x:Class="DataGridSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataGridSoHelpAttempt="clr-namespace:DataGridSoHelpAttempt"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="350" Width="525" x:Name="This">
<Window.DataContext>
    <dataGridSoHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid x:Name="MyGrid">
    <Grid.Resources>
        <dataGridSoHelpAttempt:FreezableProxyClass x:Key="ProxyElement" ProxiedDataContext="{Binding Source={x:Reference This}, Path=DataContext}"/>
    </Grid.Resources>
</Grid></Window>

如您所见 是包含网格的window 的名称。因此我不需要定义 FreezableProxyClass 的相对绑定,它直接访问主 window DataContext。 如果您在使用代码时遇到问题,我很乐意提供帮助。

此致。

我知道这听起来不太可能,但对我有用的是从样式中将 inputBinding 集合引用为 静态资源。我怀疑重要的部分是它是静态资源,不一定是我从样式中这样做的。

我的样式绑定到 TreeViewItem,而不是网格:

<Style TargetType="{x:Type TreeViewItem}">
    <Setter Property="behaviors:InputBinder.InputBindings" Value="{StaticResource itemBindings}"/>
</Style>

我的 itemBindings 资源与您的相似:

    <InputBindingCollection x:Key="itemBindings" x:Shared="False">
        <KeyBinding Command="{Binding F2Command}" Key="F2"/>
    </InputBindingCollection>

当我使用动态资源时,或者当我将绑定集合直接分配给控件时,我收到了您提到的错误消息。

附带的InputBindings属性我用的样子如下:

public static class InputBinder
{
    public static readonly DependencyProperty InputBindingsProperty = DependencyProperty.RegisterAttached
    (
        "InputBindings",
        typeof(InputBindingCollection),
        typeof(InputBinder),
        new FrameworkPropertyMetadata(new InputBindingCollection(), (sender, e) =>
        {

            var element = (UIElement)sender;
            if (element != null)
            {
                element.InputBindings.Clear();
                element.InputBindings.AddRange((InputBindingCollection)e.NewValue);
            }
        })
    );

    public static InputBindingCollection GetInputBindings(UIElement element)
    {
        return (InputBindingCollection)element.GetValue(InputBindingsProperty);
    }

    public static void SetInputBindings(UIElement element, InputBindingCollection inputBindings)
    {
        element.SetValue(InputBindingsProperty, inputBindings);
    }
}