0

I have built the following control:

MyContentControl.xaml.cs:

public partial class MyContentControl : UserControl
{
    public MyContentControl()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty MyContentProperty = DependencyProperty.Register(
        "MyContent", typeof(object), typeof(MyContentControl), new PropertyMetadata(default(object)));

    public object MyContent
    {
        get { return (object) GetValue(MyContentProperty); }
        set { SetValue(MyContentProperty, value); }
    }
}

MyContentControl.xaml:

<UserControl x:Class="MyContentControl"
             x:Name="self"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Border BorderBrush="Gray" BorderThickness="1">
            <ContentPresenter Content="{Binding ElementName=self, Path=MyContent}"/> 
        </Border>
    </Grid>
</UserControl>

And it can be used like this:

<controls:MyContentControl>
    <controls:MyContentControl.MyContent>
        <TextBox Text="Some text..."/>
    </controls:MyContentControl.MyContent>
</controls:MyContentControl>

What I would like to achieve is being able to use my control like this:

<controls:MyContentControl>
    <TextBox Text="Some text..."/>
</controls:MyContentControl>

I would like to define the inner content like I would e.g. for a StackPanel.

How can this be achieved?

mike
  • 1,627
  • 1
  • 14
  • 37
  • Any particular reason for imitating what StackPanel, DockPanel, Grid, Canvas, TabPanel would do? – XAMlMAX Aug 08 '21 at 21:31
  • @XAMlMAX: Yes, I would like to be able to simply wrap existing controls in my custom control, e.g. to provide custom design or other functionality. Is there a better way? – mike Aug 08 '21 at 23:17
  • Oh, I see. Is WrapPanel or UniformGrid of any help? Cause if you want to have a custom logic, like adding controls in a certain position then custom control derived from Panel would be best option. For "other functionality" I would suggest attached property. So you can reuse it ion other places. – XAMlMAX Aug 09 '21 at 00:47
  • If I inherit from `Panel`, can I have my own custom XAML? – mike Aug 09 '21 at 17:07
  • You could Inherit from contentcontrol rather than user control. See editrow here https://social.technet.microsoft.com/wiki/contents/articles/29777.wpf-property-list-editing.aspx – Andy Aug 09 '21 at 17:12
  • @Andy: As with the `Panel` suggestion: (how) can I have my own custom XAML? – mike Aug 09 '21 at 17:19
  • Did you not follow the link? – Andy Aug 09 '21 at 17:28
  • @Andy: Sorry for the snap back, now I see it. Thanks. It requires organizing the components in a bit differently, but may work. I'll check and see, if I have the same issues regarding named elements, see comment to lidqy's answer below. – mike Aug 09 '21 at 18:36
  • I don't follow what you mean about named elements. Each control has it's own context for names so each editrow instance has a context. When you define a control and make it the content of an editrow it's not in that editrow name context. If you wanted to reference content from editrow you could use content.property to reference. From the content you can use relativesource. – Andy Aug 09 '21 at 18:58

2 Answers2

1

You need to decorate the MyContentControl class with the ContentPropertyAttribute https://learn.microsoft.com/de-de/dotnet/api/system.windows.markup.contentpropertyattribute?view=net-5.0

[ContentProperty("MyContent")]
public partial class MyContentControl : UserControl
{ 
   ... 

Then you should be able to directly add the content without explicitly specifying "<controls:MyContentControl.MyContent>" in Property Element syntax. So that the markup below should parse and be valid:

<controls:MyContentControl>
    <TextBox Text="Some text..."/>
</controls:MyContentControl>
lidqy
  • 1,891
  • 1
  • 9
  • 11
  • This works ok, as long as the wrapped content does not have any named elements, similar to [this](https://stackoverflow.com/questions/751325/how-to-create-a-wpf-usercontrol-with-named-content) issue. – mike Aug 09 '21 at 18:30
  • btw why do you need 'MyContent'? A UserControl is a ContentControl. So you could/should just use the UserControls Content property... – lidqy Aug 09 '21 at 20:18
0

Although lidqy's answer was closest to what I had initially intended, I ended up following Andy's suggestion from the comments to the question.

The key to that approach is: the desired custom XAML is defined in a style/template, in any available resource dictionary:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:controls="clr-namespace:MyControls">
    <Style TargetType="{x:Type controls:MyContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:MyContentControl}">
                        <Grid>
                            <Border BorderBrush="Gray" BorderThickness="1">
                                <ContentPresenter/> 
                            </Border>
                        </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

The MyContentControl class then only needs to inherit ContentControl - and does not need to be a UserControl (with .xaml and xaml.cs) files.

@Andy: Regarding the question of "named elements": the exception/error is "Error MC3093: Cannot set Name attribute value 'xxx' on element 'yyy'. 'yyy' is under the scope of element 'MyContentControl', which already had a name registered when it was defined in another scope.", pretty much like here.

@lidqy: I also thought "why not just use the Content property?", but when trying I apparently created some kind of recursive binding.

Thank you, both! :o)

NOTE: The above approach should work for all ContentControls, including UserControls, enabling re-templating of basically any custom control ;o)

mike
  • 1,627
  • 1
  • 14
  • 37
  • So you don't need a custom control at all. You can just define this style for a content control. And the content of this could be defined in a data template. – XAMlMAX Aug 10 '21 at 08:26
  • 1
    @XAMlMAX: Very true. In my case the custom control is already there, the question should actually be (I know now): (How) can I re-template a control? Sometimes WPF does indeed offer pleasant suprises ;o) – mike Aug 10 '21 at 19:35