📚

Windows App SDK の ContentDialog の幅を Window の幅に追従させたい

2022/01/10に公開

先日、以下のような記事を書きました。

https://zenn.dev/okazuki/articles/contentdialog-size-limitation

これの欠点としては ContentDialog の表示中に Window のサイズを変えても表示時点で指定したプロパティの値を元に ContentDialog のサイズが決まってしまうという点です。例えば常に Window サイズの 80% くらいで ContentDialog を表示したいという動作はできません。ちょっとコードを書かないといけないです。

ロジックとしては Window のサイズ変更時に ContentDialogContent に設定しているコントロールの幅を変えてやれば OK です。例えば以下のように:

var dialogContent = new TextBlock 
{ 
    Text = "Hello world" ,
    Width = Bounds.Width * 0.8,
};
void sizeChanged(object _, WindowSizeChangedEventArgs args)
{
    dialogContent.Width = args.Size.Width * 0.8;
}

SizeChanged += sizeChanged;
var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = dialogContent,
    CloseButtonText = "Close",
};

await dialog.ShowAsync();
SizeChanged -= sizeChanged;

こうすると以下のような結果になります。

いい感じですね。毎回毎回 ContentDialog を表示するところに、こういう処理を書くのはだるいので適当にクラスにまとめてしまったりするといいと思います。

例えばこんな感じに:

class FollowWindowWidthBehavior : IDisposable
{
    private readonly FrameworkElement? _content;
    private readonly Window _window;
    private readonly Func<double, double> _calcDialogWidth;
    private bool _disposedValue;

    public FollowWindowWidthBehavior(ContentDialog contentDialog, Window window, Func<double, double> calcDialogWidth)
    {
        _window = window;
        _calcDialogWidth = calcDialogWidth;

        _content = contentDialog.Content as FrameworkElement;
        if (_content != null)
        {
            _window.SizeChanged += Window_SizeChanged;
            _content.Width = calcDialogWidth(_window.Bounds.Width);
        }
    }

    private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
    {
        _content!.Width = _calcDialogWidth(args.Size.Width);
    }

    public void Dispose()
    {
        _window.SizeChanged -= Window_SizeChanged;
    }
}

これを使うとこんな感じで書けます。

var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = new TextBlock { Text = "Hello world" },
    CloseButtonText = "Close",
};

using (new FollowWindowWidthBehavior(dialog, this, windowWidth => windowWidth * 0.8))
{
    await dialog.ShowAsync();
}

思い付きで作ったので、もっといい感じに書けるようにまとめられるかもしれません。

Microsoft (有志)

Discussion