27 August 2007 in .Net | Comments enabled
I’ve been having an issue with creating a custom re-usable UI for a WPF application I’ve been working on. After creating a UserControl and then placing a ContentPresenter control on it I found that I couldn’t name the elements that I placed within the control when used on a Window. For example:
<Window>
<Controls:MyControl>
<Button x:Name="MyButton"/>
</Controls:MyControl>
</Window>
Doing so would throw an error similar to:
Cannot set Name attribute value 'MyButton' on element 'Button'. 'Button' is under the scope of element 'MyControl', which already had a name registered when it was defined in another scope.
After spending some time on the issue and not spotting a resolution online I finally worked out what was going on. The issue arises because I created a normal UserControl in Visual Studio – the type that has a class file and a xaml file. That’s the deal breaker right there – at least in the current versions of WPF, this technique is not supported in that fashion. You must only have a class file when wanting to display named child content inside your UserControl (This applies to custom Windows as well).
This means we need to get rid of the .xaml file and add all the controls in the class file. I chose to override the OnInitialized event, create the chrome of my UserControl, assign the Content of the control to the Content property of the ContentPresenter and then assign the root UIElement I had created to the Content of the UserControl – simple as pie
And for a code example:
public class MyControl: UserControl { protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); Border border = new Border(); border.VerticalAlignment = VerticalAlignment.Stretch; border.HorizontalAlignment = HorizontalAlignment.Stretch; Grid grid = new Grid(); ContentPresenter content = new ContentPresenter(); content.Content = Content; grid.Children.Add(content); border.Child = grid; Content = border; } }
Now if we used the code at the start of this post on a Window we would get no errors and it would work perfectly.
Hope that helps,
John-Daniel Trask
9 comments. Add your own comment.
KC says 28 August 2007 @ 08:35
Dude,
I’ve not a lot a actual WPF experience, and i possibly misunderstood your solution, but are you now constructing your UI in the init method? If so, don’t you lose the advantage of allowing designers / consumers the ability to reskin your button?
traskjd says 28 August 2007 @ 09:06
Hi KC,
The example I provided is a contrived one at best. The more professional way of building such a control is to expose the chrome controls (in this case the border) on the user control to allow themeing with styles. Potentially there is a better method to override but this seemed to work fine for me.
Of course styles that are applied to types, not named instances, will still apply without being explicitly set.
You do lose the ability to design the actual UserControl in a designer (be it Blend or VS) due to the removal of the xaml file however.
As I mentioned in the post, this seems like a limitation in the current WPF implementation.
Hope that helps,
– JD
Rob Relyea says 28 August 2007 @ 09:24
I’ve blogged about this issue (naming of content inside a usercontrol) here:
http://rrelyea.spaces.live.com/Blog/cns!167AD7A5AB58D5FE!2130.entry
Thanks, Rob Relyea | Program Manager, WPF & Xaml Language Team
robrelyea.com | /blog | /wpf | /xaml
Rob says 24 August 2008 @ 17:29
This also works great if your control’s XAML is in a ResourceDictionary (like a Theme\Generic.xaml). Thanks.
…R
Lest@t says 21 December 2008 @ 00:12
I can’t name my CustomControl if it presents in another assembly. Moreover, I can’t add any event to it in desiner (using VS2008 sp1). What should I do?
((
P.S.Adding events in class file works fine, but it is not a way for me
calm says 18 February 2009 @ 23:19
nice, I liked the way you worked around the problem
lets say that I have a usercontrol that have alot of controls, styles and triggers in the xaml, how can I solve the same problem without re-adding and managing all controls and triggers in the code-behind, it like that a im asking the impossible, but really this is one of my biggest problems right now
Thanks in advance
Ryan says 17 April 2009 @ 08:22
Thanks JD, this is exactly what I have been looking for!
I have extended your idea just a little so that the control can still be mostly defined in XAML:
http://stackoverflow.com/questions/751325/how-to-create-a-wpf-usercontrol-with-named-content/757810#757810
Kev says 30 September 2009 @ 20:26
Thanks for this. Saved me no end of grief….
Kev
Massimo says 10 October 2009 @ 03:56
If we create the user control through code and set it’s style through code, then that would mean we cannot see it’s applied style at design-time, correct?
I find this utter stupidity that such a limitation exists in WPF…
Leave a Comment