0

I am building a WPF Custom Control (Note: NOT a user control). The c# code for the control is defined as follows:

using System.Windows;
using System.Windows.Controls;
using MvvmFoundation.Wpf;

namespace TextBoxWithInputBinding
{
    public class AutoComp : Control
    {
        static AutoComp()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoComp), new FrameworkPropertyMetadata(typeof(AutoComp)));
        }

        public AutoComp()
        {
            DownCommand = new RelayCommand(() =>
            {
                System.Diagnostics.Debug.WriteLine("Down");
            });
            PressedCommand = new RelayCommand(() =>
            {
                System.Diagnostics.Debug.WriteLine("Pressed");
            });
        }

        public RelayCommand DownCommand
        {
            get { return (RelayCommand)GetValue(DownCommandProperty); }
            set { SetValue(DownCommandProperty, value); }
        }

        public static readonly DependencyProperty DownCommandProperty =
            DependencyProperty.Register("DownCommand", typeof(RelayCommand), typeof(AutoComp), new PropertyMetadata(null));

        public RelayCommand PressedCommand
        {
            get { return (RelayCommand)GetValue(PressedCommandProperty); }
            set { SetValue(PressedCommandProperty, value); }
        }

        public static readonly DependencyProperty PressedCommandProperty =
            DependencyProperty.Register("PressedCommand", typeof(RelayCommand), typeof(AutoComp), new PropertyMetadata(null));
    }
}

I define the template for the control in Generic.xaml as follows:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TextBoxWithInputBinding">
    <Style TargetType="{x:Type local:AutoComp}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:AutoComp}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            >
                        <StackPanel>
                            <TextBox>
                                <TextBox.InputBindings>
                                    <KeyBinding Key="Down" Command="{TemplateBinding DownCommand}"/>
                                </TextBox.InputBindings>
                            </TextBox>
                            <Button Content="Press me" Command="{TemplateBinding PressedCommand}"/>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

When I press the "Press me" button the PressedCommand is triggered (the word "Pressed" appears in the output window - however, when I type in the TextBox and press the down key, nothing happens.

What do I need to do to make the DownCommand fire?

Adrian S
  • 514
  • 7
  • 16

2 Answers2

1

As you have already discovered you should replace the TemplateBinding with the usual binding markup and use a {RelativeSource TemplatedParent}

<KeyBinding Key="Down"
    Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DownCommand}"/>

I would still like to know why the Button binding works with TemplateBinding but the TextBox KeyBinding does not?

Because TemplateBinding is optimized and has some limitations compared to using an ordinary Binding. For example it only works directly inside the ControlTemplates's visual tree but not in DataTriggers and KeyBindings.

You will find more information about this here:

WPF TemplateBinding vs RelativeSource TemplatedParent

Community
  • 1
  • 1
mm8
  • 163,881
  • 10
  • 57
  • 88
0

So I found the answer: I need regular Binding not TemplateBinding: I replaced

<KeyBinding Key="Down" Command="{TemplateBinding DownCommand}"/>

with

<KeyBinding Key="Down"
    Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DownCommand}"/>

I would still like to know why the Button binding works with TemplateBinding but the TextBox KeyBinding does not!!!

Adrian S
  • 514
  • 7
  • 16