Click here to Skip to main content
15,866,422 members
Articles / Desktop Programming / WPF

Capturing a Content Change in a ContentPresenter

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
5 May 2016CPOL2 min read 20.9K   220   11   8
This presents a way to capture a PropertyChanged on a DependencyObject, in this case to capture when the Content on a ContentPresenter changes and setting focus.

Introduction

I had a requirement to set the initial focus on a TextBox but there was a catch. When the UserControl that contained the TextBox appeared, there was always a UserControl in the foreground that was providing busy information, or an error condition. Therefore the normal setting of focus on initialization or loading did not work. To make things even worse, I designed the main Window to use ContentPresenters whose Content was used to determine the DataTemplate to use for the ViewModel associated with the Content.

The Control

The code used to catch the change in the Content of a ContentPresenter is done by creating a new Control derived from the ContentPresenter:

C#
public class ActionableContentPresenter : ContentPresenter
{
 static ActionableContentPresenter()
 {
  ContentProperty.OverrideMetadata(typeof(ActionableContentPresenter),
   new FrameworkPropertyMetadata(new PropertyChangedCallback(OnContentChanged)));
 }

 private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
 {
  var mcc = d as ActionableContentPresenter;
  mcc?.ContentChanged?.Invoke(mcc,
        new DependencyPropertyChangedEventArgs(ContentProperty, e.OldValue, e.NewValue));
 }
 public event DependencyPropertyChangedEventHandler ContentChanged;
}

Then all that is needed in the main Window (or UserControl) is to associate an event handler to the ContentChanged event of this Control:

C#
public MainWindow()
{
 InitializeComponent();
 ActionableContentPresenter.ContentChanged += ActionableContentPresenter_ContentChanged;
}

In the case of the sample with this article, I simply check if the Content for the ActionableContentPresenter is null, and if it is, the focus can be set:

C#
private void ActionableContentPresenter_ContentChanged(object sender,
                           DependencyPropertyChangedEventArgs e)
{
 var mcc = sender as ActionableContentPresenter;
 if (mcc.Content == null )
 {
  if (DisableSetFocus.IsChecked == false)
  {
   if (SetFocusTextBox2.IsChecked == false) TextBox1.Focus();
   else TextBox2.Focus();
  }
 }
}

The Sample

The sample has a the main content which contains a number of controls, including two CheckBox controls. One of the CheckBox controls will enable the set focus and the other will changes the focus from the first TextBox to the second TextBox. When the "Show Overlay" Button is clicked, and control with a Panel with a single "Close" Button will appear. This Panel will completely overlay the other controls in the Window so only the "Close" Button can be clicked. When this Button is clicked, the overlay Control will disappear. If the "Disable Focus" CheckBox is selected, there will be no focus set to any Control on the form. However, if it is not IsChecked, then the focus will appear in either the first or the second TextBox, depending on if the "Focus on TextBox 2 (otherwise TextBox 1)" CheckBox is IsChecked.

Initial Screen

Screen after "Show Overlay" button clicked

If the "Show Alternate Content" Button is Clicked, then a Panel with a TextBox and Button will overlay all the Controls except the Button controls. If the "Show Overlay" Button is clicked, the same overlay Panel with a single Button will appear, and, if the "Disable Focus" CheckBox is not selected, the focus will be on the TextBox. Otherwise there will be no focus.

Screen after "Show Alternate Content" button is clicked

Screen after "Show Alternate Content" and then "Show Overlay" buttons are clicked

Points of Interest

This ability to connect to handlers to existing DependencyProperties should be remembered because it opens up a lot of options on doing unconventional tasks.

I have also thought about how to make this a behavior, and plan to investigate the option.

History

  • 05/05/2016: Initial version
  • 05/16/2016: Added PriorityBinding to article and code for comparison
  • 05/21/2016: Updated code to include a ContentPresentor set focus example

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Clifford Nelson Consulting
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

Comments and Discussions

 
Questionthis code would never be used in real world Pin
Member 155270507-Feb-22 12:47
Member 155270507-Feb-22 12:47 
AnswerRe: this code would never be used in real world Pin
Dave Kreskowiak26-May-22 5:40
mveDave Kreskowiak26-May-22 5:40 
PraiseMy vote of 5 Pin
CapGroupAccess29-Nov-18 10:33
CapGroupAccess29-Nov-18 10:33 
GeneralRe: My vote of 5 Pin
Member 155270507-Feb-22 12:48
Member 155270507-Feb-22 12:48 
GeneralMy vote of 5 Pin
Austin Mullins6-May-16 8:28
Austin Mullins6-May-16 8:28 
AnswerRe: My vote of 5 Pin
Clifford Nelson6-May-16 9:28
Clifford Nelson6-May-16 9:28 
QuestionWhy not just use... Pin
SledgeHammer015-May-16 13:03
SledgeHammer015-May-16 13:03 
AnswerRe: Why not just use... Pin
Clifford Nelson6-May-16 5:42
Clifford Nelson6-May-16 5:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.