How to declare event handlers inside a ControlTemplate?

I have the following ControlTemplate :

 <ControlTemplate> <Grid VerticalAlignment="Stretch" HorizontalAlignment="Left" Width="400"> <Grid.ColumnDefinitions> <ColumnDefinition Width="18" /> <ColumnDefinition Width="20*" /> <ColumnDefinition Width="20*" /> <ColumnDefinition Width="20*" /> <ColumnDefinition Width="45" /> </Grid.ColumnDefinitions> <TextBox Grid.Column="1" Template="{StaticResource watermark}" HorizontalAlignment="Stretch" Margin="4,0,0,4" Tag="Number" /> <TextBox Grid.Column="2" Template="{StaticResource watermark}" HorizontalAlignment="Stretch" Margin="4,0,0,4" Tag="Login" /> <TextBox Grid.Column="3" Template="{StaticResource watermark}" HorizontalAlignment="Stretch" Margin="4,0,0,4" Tag="Password" /> <Button Grid.Column="4" HorizontalAlignment="Stretch" Content="Add" Margin="4,0,0,4" Click="AddUser_Click"/> </Grid> </ControlTemplate> 

How to write AddUser_Click to access the text fields of the Text property?

upd: to make it clear. I know how to connect Click event handler here. The question is how to read the contents of the text fields in it, since I cannot give them a name, because they are in the template.

+4
source share
4 answers

If you have access to templatedparent (SelectedItem, FindVisualParent, etc.), you can do this if you apply the names to the text fields. Example if the ControlTemplate is for ComboBoxItem.

 private void AddUser_Click(object sender, RoutedEventArgs e) { ComboBoxItem comboBoxItem = GetVisualParent<ComboBoxItem>(button); TextBox textBox = comboBoxItem.Template.FindName("numberTextBox", comboBoxItem) as TextBox; //... } 

Another way to get TextBoxes in a ControlTemplate would be to use Visual Tree. Something like that

 private void AddUser_Click(object sender, RoutedEventArgs e) { Button button = sender as Button; Grid parentGrid = GetVisualParent<Grid>(button); List<TextBox> textBoxes = GetVisualChildCollection<TextBox>(parentGrid); foreach (TextBox textBox in textBoxes) { if (textBox.Tag == "Number") { // Do something.. } else if (textBox.Tag == "Login") { // Do something.. } else if (textBox.Tag == "Password") { // Do something.. } } } 

And the implementation of GetVisualParent and GetVisualChildCollection

 public static T GetVisualParent<T>(object childObject) where T : Visual { DependencyObject child = childObject as DependencyObject; // iteratively traverse the visual tree while ((child != null) && !(child is T)) { child = VisualTreeHelper.GetParent(child); } return child as T; } public static List<T> GetVisualChildCollection<T>(object parent) where T : Visual { List<T> visualCollection = new List<T>(); GetVisualChildCollection(parent as DependencyObject, visualCollection); return visualCollection; } private static void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual { int count = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < count; i++) { DependencyObject child = VisualTreeHelper.GetChild(parent, i); if (child is T) { visualCollection.Add(child as T); } else if (child != null) { GetVisualChildCollection(child, visualCollection); } } } 
0
source

What you can do is give Button the name "PART_Button". Then override the OnApplyTemplate method. In code you can do

 var btn = this.Template.FindName("PART_Button", this) as Button; btn.Click += ... 
+17
source

The class is searched in the event handler, which corresponds to the x:Class directive of the current files, which allows you to add a built-in event handler without having to redefine the class and override OnApplyTemplate with the addition of handlers, regardless of where you declare the ControlTemplate.

MainWindow.xaml:

 <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Button Content="asdf"> <Button.Style> <Style TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Button Content="{TemplateBinding Content}" Click="Button_Click"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </Button.Style> </Button> </Window> 

MainWindow.xaml.cs:

 using System.Windows; namespace WpfApplication1 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Button clicked!"); } } } 
+4
source

I was not lucky to find my flag, PART_CheckBox, using

  this.Template.FindName("control name", this) 

method but

  GetTemplateChild("control name") 

have worked.

'ResourceDictionary' stub

 <Style x:Key="OGrid" TargetType="{x:Type local:OrientationGrid}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:OrientationGrid}" x:Name="PART_Control"> <CheckBox x:Name="PART_CheckBox"/> ... 

User control, OrientationGrid, stub:

  public override void OnApplyTemplate() { base.OnApplyTemplate(); CheckBox chkbx = GetTemplateChild("PART_CheckBox") as CheckBox; chkbx.Checked += Chkbx_Checked; } private void Chkbx_Checked(object sender, RoutedEventArgs e) { MessageBox.Show("Event Raised"); } ... 

based answer: WPF gets an element from a template in code

0
source

All Articles