Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a WPF UserControl with NAMED content

I have a set of controls with attached commands and logic that are constantly reused in the same way. I decided to create a user control that holds all the common controls and logic.

However I also need the control to be able to hold content that can be named. I tried the following:

<UserControl.ContentTemplate>     <DataTemplate>         <Button>a reused button</Button>         <ContentPresenter Content="{TemplateBinding Content}"/>         <Button>a reused button</Button>     </DataTemplate> </UserControl.ContentTemplate> 

However it seems any content placed inside the user control cannot be named. For example if I use the control in the following way:

<lib:UserControl1>      <Button Name="buttonName">content</Button> </lib:UserControl1> 

I receive the following error:

Cannot set Name attribute value 'buttonName' on element 'Button'. 'Button' is under the scope of element 'UserControl1', which already had a name registered when it was defined in another scope.

If I remove the buttonName, then it compiles, however I need to be able to name the content. How can I achieve this?

like image 883
Ryan Avatar asked Apr 15 '09 11:04

Ryan


People also ask

What is UserControl WPF?

User controls, in WPF represented by the UserControl class, is the concept of grouping markup and code into a reusable container, so that the same interface, with the same functionality, can be used in several different places and even across several applications.

What is the difference between UserControl and window in WPF?

A window is managed by the OS and is placed on the desktop. A UserControl is managed by wpf and is placed in a Window or in another UserControl. Applcations could be created by have a single Window and displaying lots of UserControls in that Window.

How do I add user control to XAML?

The XamlFileBrowser Control Create a XAML application using Visual Studio 2008 and add a new item by right clicking on the project, select Add >> New Item from the menu and select User Control from the available templates.


2 Answers

The answer is to not use a UserControl to do it.

Create a class that extends ContentControl

public class MyFunkyControl : ContentControl {     public static readonly DependencyProperty HeadingProperty =         DependencyProperty.Register("Heading", typeof(string),         typeof(MyFunkyControl), new PropertyMetadata(HeadingChanged));      private static void HeadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)     {         ((MyFunkyControl) d).Heading = e.NewValue as string;     }      public string Heading { get; set; } } 

then use a style to specify the contents

<Style TargetType="control:MyFunkyControl">     <Setter Property="Template">         <Setter.Value>             <ControlTemplate TargetType="control:MyFunkyControl">                 <Grid>                     <ContentControl Content="{TemplateBinding Content}"/>                 </Grid>             </ControlTemplate>         </Setter.Value>     </Setter> </Style> 

and finally - use it

<control:MyFunkyControl Heading="Some heading!">                 <Label Name="WithAName">Some cool content</Label> </control:MyFunkyControl> 
like image 120
Sybrand Avatar answered Sep 20 '22 18:09

Sybrand


It seems this is not possible when XAML is used. Custom controls seem to be a overkill when I actually have all the controls I need, but just need to group them together with a small bit of logic and allow named content.

The solution on JD's blog as mackenir suggests, seems to have the best compromise. A way to extend JD's solution to allow controls to still be defined in XAML could be as follows:

    protected override void OnInitialized(EventArgs e)     {         base.OnInitialized(e);          var grid = new Grid();         var content = new ContentPresenter                           {                               Content = Content                           };          var userControl = new UserControlDefinedInXAML();         userControl.aStackPanel.Children.Add(content);          grid.Children.Add(userControl);         Content = grid;                } 

In my example above I have created a user control called UserControlDefinedInXAML which is define like any normal user controls using XAML. In my UserControlDefinedInXAML I have a StackPanel called aStackPanel within which I want my named content to appear.

like image 23
Ryan Avatar answered Sep 20 '22 18:09

Ryan