Ensuring AdornmentDecorator within a ContentPresenter, but without a ControlTemplate

663 Views Asked by At

I've searched around quite a bit and can't seem to crack this nut.

I've got an app with a main view that changes dynamically, and to do this I use content presenter with a binding to a control:

    <ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
        <StackPanel Margin="20,20,20,500">
            <ContentPresenter Content="{Binding MainControl}"/>
        </StackPanel>
    </ScrollViewer>

Then I change the MainControl at runtime in my view model. The problem is that the controls getting bound don't reliably display their error templates... I suspect it is for the reasons discussed here:

Validation ErrorTemplate not showing on data errors

But the fix for this problem doesn't seem to work for me because I'm not using a control template around my content presenter. When I wrap an AdornmentDecorator tag around my content presenter, it doesn't seem to fix the problem. It DOES work if I put an AdornmentDecorator inside each control I load into the contentpresenter (as the root element), but I'd like to avoid this repetition if possible.

Any insights?

UPDATE

I tried this approach suggested by Dennis, but to no avail. The control binds okay, but it works no better than the current approach (also shown commented below). Note: I tried it both with the AdornerDecorator as a singleton element the way Dennis has it, and surrounding the ContentPresenter, as shown below. Neither show any difference - the adorners around my controls all disappear when the MainControl binding is changed.

<UserControl.Resources>
    <Style x:Key="MainContentControl" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Grid>
                        <AdornerDecorator>
                            <ContentPresenter Content="{Binding MainControl}"/>
                        </AdornerDecorator>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</UserControl.Resources>
<Grid>

     .....


    <ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
        <StackPanel Margin="20,20,20,500" >
            <ContentControl Style="{StaticResource MainContentControl}"/>
        </StackPanel>
    </ScrollViewer>

    <!-- THE BELOW WORKS IF I SURROUND EACH BOUND CONTROL WITH adornerdecorator -->
    <ScrollViewer Grid.Column="2" x:Name="StepScrollViewer">
        <StackPanel Margin="20,20,20,500">
            <ContentPresenter Content="{Binding MainControl}"/>
        </StackPanel>
    </ScrollViewer>
    -->
1

There are 1 best solutions below

3
On

Instead of using a ContentPresenter directly, I would instead use a ContentControl. A ContentControl is the base class for controls that contain other elements and have a Content property, e.g. Button.

Then you can override the template to have an AdornerDecorator next to the ContentControl. This is different to what you previously tried as now the ContentPresenter is part of the same visual tree as the Adorner.

<Style TargetType="{x:Type ContentControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ContentControl}">
                <AdornerDecorator>
                    <ContentPresenter/>
                </AdornerDecorator>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Edit: Forgot that the AdornerDecorator needs to wrap the container, not just sit side-by-side.