I have a couple of TextBox on the frame, I changed their style so that their DeleteButton would DeleteButton be visible. However, these boxes do not respond to a click if their IsReadOnly property is true . I have assigned a new click handler, but now I need to determine which TextBox the clear button pressed. So, how to determine the parent of the button in this event?

Update, I did not insert it.

 private void DeleteButton_Click(object sender, RoutedEventArgs e) { //var parent = ((Button) sender).Parent;? } 

A piece of TextBox style:

 <Button x:Name="DeleteButton" BorderThickness="{TemplateBinding BorderThickness}" Grid.Column="1" FontSize="{TemplateBinding FontSize}" IsTabStop="False" Margin="{ThemeResource HelperButtonThemePadding}" MinWidth="34" Grid.Row="1" Style="{StaticResource DeleteButtonStyle}" Visibility="Visible" VerticalAlignment="Stretch" Click="DeleteButton_Click"/> 
  • In theory, if this handler is subscribed to the events of each TextBox, then the object (specific TextBox) that raised the event is in the sender. - iluxa1810
  • @ iluxa1810, sorry, I accidentally inserted it wrong. Now fixed. - Aynur Sibagatullin
  • The subscription code for this handler would not hurt either. - iluxa1810

1 answer 1

The easiest is probably this:

 DependencyObject o = (DependencyObject)sender; while (!(o is TextBox)) o = VisualTreeHelper.GetParent(o); TextBox textBox = (TextBox)o; 

Explanation: in your TextBox visual tree is the ancestor of Button . The VisualTreeHelper.GetParent function returns you to your immediate ancestor, and you will have to “walk” upwards several levels until you reach the TextBox .

If you want to protect your code from possible errors, it makes sense to check whether you have rested against the root element, if for some reason you are not inside TextBox 'a:

 DependencyObject o = (DependencyObject)sender; while (o != null && !(o is TextBox)) o = VisualTreeHelper.GetParent(o); if (o == null) { // вы не внутри TextBox'а, что делаем? } else { TextBox textBox = (TextBox)o; // всё хорошо, работаем } 

Another option: put the desired element in the markup in the Tag :

 <Button x:Name="DeleteButton" ... Click="DeleteButton_Click" Tag="{Binding RelativeSource={RelativeSource TemplatedParent}}"/> 

and in code-behind

 Button button = (Button)sender; TextBox textBox = (TextBox)button.Tag; 

Again, if in doubt, more checks can be made in the code:

 TextBox textBox = (sender as RichTextBlock)?.Tag as TextBox; if (textBox == null) { // что-то пошло не так } 
  • @DenisBubnov: Added comments and code with precautions. - VladD
  • So much clearer and easier to understand. Thanks for the full answer - Denis Bubnov
  • @DenisBubnov: And thank you, without your clue, the answer would be worse. - VladD