Search code examples
c#.netwpfxamlcontentpresenter

Simple popup dialog in WPF (overlay inside Window)


I'm working on a modal dialog popup (I'm not sure about the exact UX term) that is displayed inline, inside of a control or window with darkened background.

Visual example

example

What I tried is putting a <ContentPresenter /> inside the XAML of the popup and then just instantiate it like this:

<local:Popup Grid.RowSpan="2">
    <TextBlock Text="Popup test..." />
</local:Popup>

However, the XAML replaces the entire Popup XAML instead of being placed where the ContentPresenter is.

Q: How is the ContentPresenter here used properly?

Popup.xaml

<ContentControl
    x:Class="[...].Popup"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:[...]"
    mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="300">
    <Grid Background="#7f000000">
        <Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
            <StackPanel Margin="20">
                <TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="20" />
                <ContentPresenter />
            </StackPanel>
        </Grid>
    </Grid>
</ContentControl>

Popup.xaml.cs

using System.Windows;

namespace [...]
{
    public partial class Popup : ContentControlBase
    {
        public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
        public string Title
        {
            get
            {
                return (string)GetValue(TitleProperty);
            }
            set
            {
                SetValue(TitleProperty, value);
            }
        }

        public Popup()
        {
            InitializeComponent();
        }
    }
}

Solution

  • The content of your Popup should be defined as a ControlTemplate for the ContentPresenter to work as expected here. Please refer to the following sample code.

    Popup.xaml:

    <ContentControl
    x:Class="WpfApplication1.Popup"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="300"
    x:Name="popup">
    <ContentControl.Template>
        <ControlTemplate TargetType="local:Popup">
            <Grid Background="#7f000000">
                <Grid Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
                    <StackPanel Margin="20">
                        <TextBlock Text="{Binding Title, ElementName=popup}" FontSize="20" />
                        <ContentPresenter />
                    </StackPanel>
                </Grid>
            </Grid>
        </ControlTemplate>
    </ContentControl.Template>
    

    Popup1.xaml.cs.

    public partial class Popup : ContentControl
    {
        public static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Popup));
        public string Title
        {
            get
            {
                return (string)GetValue(TitleProperty);
            }
            set
            {
                SetValue(TitleProperty, value);
            }
        }
    
        public Popup()
        {
            InitializeComponent();
        }
    }
    

    }

    Window1.xaml:

    <local:Popup Title="Title...">
         <TextBlock>Text...</TextBlock>
    </local:Popup>