Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF UserControl inside another UserControl

I'm looking to set a UserControl to be the Content of another UserControl in XAML, in the same way you can set a Button's Content to be anything.

Let's say my "outer" UserControl looks like this:

<MyUserControl>
   <Grid>
      <Border FancyPantsStyling="True">

         <-- I want to insert other controls here -->

      </Border>
   </Grid>
</MyUserControl>

And I'd like to instantiate this way:

<local:MyUserControl>
   <local:MyUserControl.Content>
      <local:AnotherControl />
   </local:MyUserControl.Content>
</local:MyUserControl>

How do I design MyUserControl to render it's Content in a specific location?

like image 703
bufferz Avatar asked Oct 16 '10 17:10

bufferz


2 Answers

All the stuff you put into your UserControl's XAML is its Content so you can't inject something else by setting the Content property. There are a few different ways you could handle this. If you don't have anything in the code-behind for MyUserControl you can just get rid of it and use something like:

<ContentControl>
    <ContentControl.Template>
        <ControlTemplate TargetType="{x:Type ContentControl}">
            <Grid>
                <Border FancyPantsStyling="True">
                    <ContentPresenter/>
                </Border>
            </Grid>
        </ControlTemplate>
    </ContentControl.Template>

    <local:AnotherControl/>
</ContentControl>

If you have code behind that doesn't access the XAML elements directly you can do a similar thing with your existing control (since UC derives from ContentControl):

<local:MyUserControl>
    <local:MyUserControl.Template>
        <ControlTemplate TargetType="{x:Type local:MyUserControl}">
            <Grid>
                <Border FancyPantsStyling="True">
                    <ContentPresenter/>
                </Border>
            </Grid>
        </ControlTemplate>
    </local:MyUserControl.Template>
</local:MyUserControl>

If you need to keep the existing content connected to your code-behind you can use a DataTemplate to pass in the external content (into a new DP on MyUserControl) and apply that template to a ContentControl in the UC's XAML.

like image 191
John Bowen Avatar answered Nov 17 '22 16:11

John Bowen


I got an idea, then tried it and it worked for me. I just wanted to share this to other people. I hope it will be useful.

The video link which explains what is the end of the solution: Video Linkenter image description here

The basic idea is to create UIElement DependencyProperty instead of creating Border DependencyProperty

Firstly, you should add your borders or panels or whatever you want to your user control (in your case it'S "MyUserControl") and make sure it has a name to access from .cs file:

 <Border x:Name="LeftBorder" Grid.Column="0">

Then you should add a public UIElement value to your user control (in your case it's "MyUserControl"):

    public UIElement LeftBorderChild
    {
        get { return (UIElement)GetValue(LeftBorderChildProperty ); }
        set { SetValue(LeftBorderChildProperty , value); }
    }

Secondly, type of your Dependencyproperty must be UIElement:

public static readonly DependencyProperty LeftBorderChildProperty = DependencyProperty.Register("LeftBorderChild", typeof(UIElement), typeof(MyUserControl), new PropertyMetadata(new PropertyChangedCallback(LeftBorderChildChanged)));

After these, typing events:

    public static void LeftBorderChildChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyUserControl thisUserControl = d as MyUserControl; 
        thisCombobox._LeftBorderChildChanged(e); // Calling local event. The new child will be added in this local event function.
    }
    public void _LeftBorderChildChanged(DependencyPropertyChangedEventArgs e)
    {
        // In this function, new child element will be added to inside of LeftBorder
        this.LeftBorder.Child = (UIElement)e.NewValue; // Sets left border child
    }

We're done with this class. Let's call it from other class and add a control inside of it.

 <local:MyUserControl Width="312" HorizontalAlignment="Right"
                                Margin="48, 0, 0, 0" VerticalAlignment="Center"
                                Height="56"  >
                <local:MyUserControl.LeftBorder>
                    <-- You can insert another control here -->
                    <-- Just don't remember that if you want to add more than one controls, you should add a panel then add controls into inside of the panel because Border child can only 1 child item -->
                    <StackPanel>
                    <-- Now you can insert your controls -->
                    </StackPanel>
                </local:MyUserControl.LeftBorder>
            </local:MyUserControl>

Note: When you do this firstly, you have to run your program before viewing in xaml designer. After running your program, all design systems are going to run synchronously. I hope i understood what you mean and answered correctly. Thank You

like image 1
Yusufhaystra Avatar answered Nov 17 '22 17:11

Yusufhaystra