繁体   English   中英

KeyBinding用作UserControl,但在XAML中使用属性元素语法时则不行

[英]KeyBinding works as UserControl but not when pusing property element syntax in XAML

正如标题所述,我在使用属性元素语法时无法使KeyBinding起作用。 通过工作我的意思是使用Ctrl+Del组合键来更改列表框的背景颜色。 可以使用键组合或单击按钮,这两个按钮都会调用该命令,但从不调用该命令。 在调试模式下设置断点时,永远不会遇到断点。

我已经遵循文档中的InputBinding类示例 ,并且只能在使用UserControl时使KeyBinding工作,并且想要理解为什么会这样,以及我做错了什么

下面是一个MVCE,用于表示使用属性元素语法声明的代码不起作用。 注释掉是UserControl的一行,它封装了StackPanel并允许KeyBinding工作。 依赖于注释掉每个PropertyElementSyntax区域并取消注释MainWindow.xaml.cs后面代码中的每个UserControlSyntax区域。

MainWindow.xaml:

<Window x:Class="LearningKeyBindingWPFApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:LearningKeyBindingWPFApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <!--<local:UserControl1 x:Name="CustomColorPicker" />-->
    <StackPanel Margin="0,40,0,0">
        <StackPanel.InputBindings>
            <KeyBinding Command="{Binding ChangeColorCommand}"
                        CommandParameter="{Binding ElementName=ColorPicker, Path=SelectedItem}"
                        Key="{Binding ChangeColorCommand.Key}"
                        Modifiers="{Binding ChangeColorCommand.ModifierKeys}" />
            <MouseBinding Command="{Binding ChangeColorCommand}"
                          CommandParameter="{Binding ElementName=ColorPicker, Path=SelectedItem}"
                          MouseAction="{Binding ChangeColorCommand.MouseAction}" />
        </StackPanel.InputBindings>
        <Button Content="Change Color" 
                Command="{Binding ChangeColorCommand}"
                CommandParameter="{Binding ElementName=ColorPicker, Path=SelectedItem}" />
        <ListBox Name="ColorPicker"
                 xmlns:sys="clr-namespace:System;assembly=mscorlib"
                 SelectedIndex="0">
            <sys:String>Red</sys:String>
            <sys:String>Green</sys:String>
            <sys:String>Blue</sys:String>
            <sys:String>Yellow</sys:String>
            <sys:String>Orange</sys:String>
            <sys:String>Purple</sys:String>
        </ListBox>
    </StackPanel>
</Window>

MainWindow.xaml.cs的代码隐藏:

public MainWindow()
{
    DataContext = this;

    InitializeComponent();
    InitializeCommand();

    #region UserControlSyntax
    //CustomColorPicker.ColorPicker.Focus();
    #endregion

    #region PropertyElementSyntax
    ColorPicker.Focus();
    #endregion
}

public SimpleDelegateCommand ChangeColorCommand { get; private set; }

private SolidColorBrush _originalColor;

private void InitializeCommand()
{
    #region UserControlSyntax
    //_originalColor = (SolidColorBrush)CustomColorPicker.ColorPicker.Background;
    #endregion

    #region PropertyElementSyntax
    _originalColor = (SolidColorBrush)ColorPicker.Background;
    #endregion

    ChangeColorCommand = new SimpleDelegateCommand(ChangeColor)
    {
        Key = Key.Delete,
        ModifierKeys = ModifierKeys.Control
    };
}

private void ChangeColor(object colorString)
{
    if (colorString == null)
    {
        return;
    }

    var selectedColor = SelectedColor((string)colorString);

    #region UserControlSyntax
    //if (CustomColorPicker.ColorPicker.Background == null)
    //{
    //    CustomColorPicker.ColorPicker.Background = selectedColor;
    //    return;
    //}

    //CustomColorPicker.ColorPicker.Background = ((SolidColorBrush)CustomColorPicker.ColorPicker.Background).Color == selectedColor.Color
    //        ? _originalColor
    //        : selectedColor;
    #endregion

    #region PropertyElementSyntax
    if (ColorPicker.Background == null)
    {
        ColorPicker.Background = selectedColor;
        return;
    }

    var isColorIdentical = ((SolidColorBrush)ColorPicker.Background).Color == selectedColor.Color;
    ColorPicker.Background = isColorIdentical
            ? _originalColor
            : selectedColor;
    #endregion
}

private SolidColorBrush SelectedColor(string value)
{
    #region UserControlSyntax
    //var selectedColor = (Color)ColorConverter.ConvertFromString(value);
    #endregion

    #region PropertyElementSyntax
    var selectedColor = (Color)ColorConverter.ConvertFromString((string)ColorPicker.SelectedItem);
    #endregion

    return new SolidColorBrush(selectedColor);
}

问题是在no- UserControl场景中, DataContext是在初始化命令对象之前设置的。

WPF有一个健壮的绑定系统,但它通常依赖于属性更改通知,通过INotifyPropertyChanged 只要您获得正确的操作顺序,某些方案就可以在没有它的情况下工作。 但是,如果没有属性更改通知,如果您错过了向WPF提供某些属性值的机会窗口,那么以后就不会再尝试了。

使用UserControl时,在设置ChangeColorCommand属性后,将初始化UserControl的绑定。 这只是WPF如何初始化UI树中各种对象的工件。 但这意味着,当UserControl的绑定查看ChangeColorCommand属性时,它具有您想要的值。

另一方面,当您将StackPanel显式放入窗口的XAML时,在设置WPF的属性以查看它时为时已太晚。 它已在InitializeComponent()调用期间解析了这些绑定。 稍后设置属性无效。

根据您现有的代码,有几种方法可以解决这个问题:

  1. 最简单的是只移动DataContext = this;的赋值DataContext = this; 调用InitializeCommand() 更新DataContext需要WPF更新所有依赖绑定,因此在InitializeCommand()调用之后执行此操作可确保该属性具有所需的值。
  2. MainWindow类中实现INotifyPropertyChanged ,并在设置时为ChangeColorCommand属性引发PropertyChanged事件。 这将让WPF知道值已更改,并且应该重新评估依赖于它的任何绑定。

所有这些,我再往前走一步:

  1. 使用INotifyPropertyChangedChangeColorCommand实现适当的视图模型对象,并将用作数据上下文。 使UI对象具有双重功能,因为UI和属性绑定源(即视图模型的工作)不适合普通的WPF模型,牺牲了MVVM通常会提供的好处,当然还会引入这种奇怪的时机不清楚为什么属性绑定没有按预期工作的事情。


好的,从技术上讲,你可以采用第四种方法,即在InitializeCommand()之前调用InitializeComponent() 主要问题是,目前它依赖于直接检索UI对象属性的值,并且该UI对象在调用InitializeComponent()之后才会存在。

这让我回到了上面的#3选项。 事实上,您不应该直接访问UI对象属性。 这应该是视图模型中的另一个属性,您应该更直接地选择初始颜色应该是什么,而不仅仅是在启动时从UI中抓取它。

我承认,这里有一些摆设空间,但你应该尽量保持你的视图模型和UI代码彼此脱节。

暂无
暂无

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

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