I’m making a custom control for a particular UI I am creating. Ideally, the user inputs a number into some textboxes, and upon pressing enter, those numbers get saved and can be used later in the program. I’ve narrowed down the program into the simplest terms to explain the problem. First I have two custom controls as follows:
public class OuterCC : Control
{
public InnerCC CompA
{
get { return (InnerCC)GetValue(CompAProperty); }
set { SetValue(CompAProperty, value); }
}
public static readonly DependencyProperty CompAProperty =
DependencyProperty.Register("CompA", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public InnerCC CompB
{
get { return (InnerCC)GetValue(CompBProperty); }
set { SetValue(CompBProperty, value); }
}
public static readonly DependencyProperty CompBProperty =
DependencyProperty.Register("CompB", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public InnerCC CompC
{
get { return (InnerCC)GetValue(CompCProperty); }
set { SetValue(CompCProperty, value); }
}
public static readonly DependencyProperty CompCProperty =
DependencyProperty.Register("CompC", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public InnerCC CompD
{
get { return (InnerCC)GetValue(CompDProperty); }
set { SetValue(CompDProperty, value); }
}
public static readonly DependencyProperty CompDProperty =
DependencyProperty.Register("CompD", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public InnerCC CompE
{
get { return (InnerCC)GetValue(CompEProperty); }
set { SetValue(CompEProperty, value); }
}
public static readonly DependencyProperty CompEProperty =
DependencyProperty.Register("CompE", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public InnerCC CompF
{
get { return (InnerCC)GetValue(CompFProperty); }
set { SetValue(CompFProperty, value); }
}
public static readonly DependencyProperty CompFProperty =
DependencyProperty.Register("CompF", typeof(InnerCC), typeof(OuterCC), new PropertyMetadata(null));
public OuterCC()
{
CompA = new InnerCC();
CompB = new InnerCC();
CompC = new InnerCC();
CompD = new InnerCC();
CompE = new InnerCC();
CompF = new InnerCC();
}
static OuterCC()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(OuterCC), new FrameworkPropertyMetadata(typeof(OuterCC)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
CompA = (InnerCC)GetTemplateChild("PART_compA");
CompB = (InnerCC)GetTemplateChild("PART_compB");
CompC = (InnerCC)GetTemplateChild("PART_compC");
CompD = (InnerCC)GetTemplateChild("PART_compD");
CompE = (InnerCC)GetTemplateChild("PART_compE");
CompF = (InnerCC)GetTemplateChild("PART_compF");
CompA.Index = 1;
CompB.Index = 2;
CompC.Index = 3;
CompD.Index = 4;
CompE.Index = 5;
CompF.Index = 6;
}
}
public class InnerCC : Control
{
public int Index
{
get { return (int)GetValue(IndexProperty); }
set { SetValue(IndexProperty, value); }
}
public static readonly DependencyProperty IndexProperty =
DependencyProperty.Register("Index", typeof(int), typeof(InnerCC), new PropertyMetadata(0));
static InnerCC()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(InnerCC), new FrameworkPropertyMetadata(typeof(InnerCC)));
}
}
public class ThicknessDivisionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Thickness thick = (Thickness)value;
string str = (string)parameter;
double divisor = Double.Parse(str);
thick.Right /= divisor;
thick.Left /= divisor;
thick.Top /= divisor;
thick.Bottom /= divisor;
return thick;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class DoubleDivisionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double dividend = (double)value;
string str = (string)parameter;
double divisor = Double.Parse(str);
dividend /= divisor;
return dividend;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Here is my generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Testing"
xmlns:cc="clr-namespace:Testing.CustomControls">
<Style TargetType="{x:Type cc:OuterCC}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cc:OuterCC}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<cc:InnerCC x:Name="PART_compA"/>
<cc:InnerCC x:Name="PART_compB"/>
<cc:InnerCC x:Name="PART_compC"/>
<cc:InnerCC x:Name="PART_compD"/>
<cc:InnerCC x:Name="PART_compE"/>
<cc:InnerCC x:Name="PART_compF"/>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type cc:InnerCC}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type cc:InnerCC}">
<ControlTemplate.Resources>
<cc:ThicknessDivisionConverter x:Key="ThicknessDivisionConverter"/>
<cc:DoubleDivisionConverter x:Key="DoubleDivisionConverter"/>
</ControlTemplate.Resources>
<TextBox BorderBrush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border},Path=BorderBrush}"
BorderThickness="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Border},Path=BorderThickness,Converter={StaticResource ThicknessDivisionConverter},ConverterParameter=2.0}"
Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel},Path=ActualHeight,Converter={StaticResource DoubleDivisionConverter},ConverterParameter=6.0}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
My mainwindow.xaml is just as simple as possible to just test out different theories of why its not working
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<cc:OuterCC x:Name="TestInput" BorderBrush="Black" BorderThickness="5" />
</Grid>
<Grid Grid.Column="1">
<TextBox x:Name="TestTextBox" Height="100"/>
</Grid>
</Grid>
And finally my mainwindow
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TestInput.CompA.KeyDown += TestInput_KeyDown;
TestTextBox.KeyDown += TestInput_KeyDown;
}
private void TestInput_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
}
}
}
If I set the debugger to pause the program when TestInput_KeyDown() is called, it will pause when I make a press any key in the normal textbox. However it is never called when I press a key in the custom control textbox. I’ve been troubleshooting this for over a day now and googling hasn’t been able to get me anywhere. I’m a self-taught coder from youtube and google, is there something I am missing of why I can’t get my custom control textboxes to activate key downs?
Other things I’ve tried: setting the focusable to true for innerCC, outerCC, and the main window, both separately and all together to see if that does anything. I’ve tried setting up RoutedEventHandlers in the custom controls. I’ve tried having InnerCC inherit from TextBox instead of Control.
Any help would be appreciated.
Mark Johnson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.