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