Search code examples
c#winui-3contentdialog

WinUI 3: Change ContentDialog Size Programmatically While ContentDialog is Open


I've added two buttons, with only one visible at a time, to adjust the size of a ContentDialog. I want there to be two sizes: maximum, which would be sized to fill the parent window, or the default "restored" size. It's somewhat similar to standard Windows Maximize and Restore buttons.

I've found that I can use the ContentDialog.Resources with the keys "ContentDialogMaxWidth" and "ContentDialogMaxHeight" in XAML to set one or the other desired sizes, as shown below.

Default size in XAML:

<ContentDialog.Resources>
    <x:Double x:Key="ContentDialogMaxWidth">800</x:Double>
    <x:Double x:Key="ContentDialogMaxHeight">1000</x:Double>
</ContentDialog.Resources>

Maximum size in XAML:

<ContentDialog.Resources>
    <x:Double x:Key="ContentDialogMaxWidth">2000</x:Double>
    <x:Double x:Key="ContentDialogMaxHeight">2000</x:Double>
</ContentDialog.Resources>

However, the above XAML only sets the size once when the ContentDialog opens. I can't seem to change it dynamically after it is opened.

Below are the click events for the two buttons. I've tried to change the two resources shown above dynamically in the events. Even though the resource values are changing (I've tested this), the dialog size does not update.

Is there another way to change the ContentDialog to the desired sizes using the button events?

    private void MaximizeDialogButton_Click(object sender, RoutedEventArgs e)
    {
        this.FullSizeDesired = true;
        this.Resources["ContentDialogMaxWidth"] = 2000;
        this.Resources["ContentDialogMaxHeight"] = 2000;
        this.MaximizeDialogButton.Visibility = Visibility.Collapsed;
        this.RestoreDialogButton.Visibility = Visibility.Visible;
    }

    private void RestoreDialogButton_Click(object sender, RoutedEventArgs e)
    {
        this.FullSizeDesired = false;
        this.Resources["ContentDialogMaxWidth"] = 800;
        this.Resources["ContentDialogMaxHeight"] = 1000;
        this.Width = 800;
        this.Height = 1000;
        this.MaximizeDialogButton.Visibility = Visibility.Visible;
        this.RestoreDialogButton.Visibility = Visibility.Collapsed;
    }

Solution

  • It seems that ContentDialog doesn't support that. Instead, you can create a custom dialog using the WinUIEx NuGet package.

    For example:

    WindowDialog.xaml

    <ex:WindowEx
        x:Class="WinUIDemoApp.WindowDialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:ex="using:WinUIEx"
        xmlns:local="using:WinUIDemoApp"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid RowDefinitions="*,Auto">
            <StackPanel
                Grid.Row="0"
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
                <NumberBox
                    x:Name="WidthNumberBox"
                    ValueChanged="WidthNumberBox_ValueChanged" />
                <NumberBox
                    x:Name="HeightNumberBox"
                    ValueChanged="HeightNumberBox_ValueChanged" />
            </StackPanel>
            <Grid
                Grid.Row="1"
                ColumnDefinitions="*,*">
                <Button
                    Grid.Column="0"
                    Click="OKButton_Click"
                    Content="OK" />
                <Button
                    Grid.Column="1"
                    Click="CancelButton_Click"
                    Content="Cancel" />
            </Grid>
        </Grid>
    
    </ex:WindowEx>
    

    WindowDialog.xaml.cs

    using Microsoft.UI.Xaml;
    using System.Threading.Tasks;
    using WinUIEx;
    
    namespace WinUIDemoApp;
    
    public enum WindowDialogResult
    {
        Cancel,
        OK,
    }
    
    public partial class WindowDialog : WindowEx
    {
        private TaskCompletionSource<WindowDialogResult>? _taskCompletionSource;
    
        public WindowDialog()
        {
            InitializeComponent();
            IsAlwaysOnTop = true;
            this.CenterOnScreen();
        }
    
        public new object? Content { get; set; }
    
        public Task<WindowDialogResult> ShowAsync()
        {
            WidthNumberBox.Value = Width;
            HeightNumberBox.Value = Height;
    
            _taskCompletionSource = new();
    
            this.Activate();
    
            return _taskCompletionSource.Task;
        }
    
        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            _taskCompletionSource?.SetResult(WindowDialogResult.OK);
            this.Close();
        }
    
        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            _taskCompletionSource?.SetResult(WindowDialogResult.Cancel);
            this.Close();
        }
    
        private void WidthNumberBox_ValueChanged(Microsoft.UI.Xaml.Controls.NumberBox sender, Microsoft.UI.Xaml.Controls.NumberBoxValueChangedEventArgs args)
        {
            Width = (float)sender.Value;
        }
    
        private void HeightNumberBox_ValueChanged(Microsoft.UI.Xaml.Controls.NumberBox sender, Microsoft.UI.Xaml.Controls.NumberBoxValueChangedEventArgs args)
        {
            Height = (float)sender.Value;
        }
    }
    

    then you can use it like this:

    WindowDialog dialog = new();
    WindowDialogResult result = await dialog.ShowAsync();