🐙

Windows App SDK の ContentDialog の横幅をひろげたい

2022/01/10に公開
6

Windows App SDK の Windows UI Library で任意のコンテンツをホストしているダイアログを出すために使う ContentDialog ですが、こいつ実は横幅の最大値に制限があって結構簡単に制限にひっかかります…。

ContentDialog の generic.xaml に <x:Double x:Key="ContentDialogMaxWidth">548</x:Double> という形でハードコードされているみたいです。

https://github.com/microsoft/microsoft-ui-xaml/issues/424

実際に見てみましょう。

以下のようなコードを適当なボタンクリックイベントに書きます。

var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = string.Join(
        ", ", 
        Enumerable.Range(0, 100).Select(_ => Guid.NewGuid().ToString())),
    CloseButtonText = "Close",
};
await dialog.ShowAsync();

実行すると以下のようになります。ウィンドウ幅は結構余裕があるので、もう少し大きく出て欲しいですよね…。

なので、ウィンドウのサイズが変わるとちょっと不都合がおきますが、とりあえず以下のようにして表示時点のウィンドウサイズの 80% まで幅がひろがるようにしたいという感じにしてみました。

var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = string.Join(
        ", ", 
        Enumerable.Range(0, 100).Select(_ => Guid.NewGuid().ToString())),
    CloseButtonText = "Close",
    MaxWidth = Bounds.Width * 0.8, // ウィンドウの幅の 80% まではひろがって欲しい
};
await dialog.ShowAsync();

何故か左に寄ってしまいます…

ということで正しい対処方法は、リソースに ContentDialogMaxWidth というキーで ContentDialog が取りうる最大の幅を定義してあげる形になります。

例えば幅 5000 までの場合は以下のように指定します。

App.xaml
<Application
    x:Class="App9.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App9">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
                <!--  Other merged dictionaries here  -->
            </ResourceDictionary.MergedDictionaries>
            <!--  Other app resources here  -->
            <!--  以下の行を追加  -->
            <x:Double x:Key="ContentDialogMaxWidth">5000</x:Double>
        </ResourceDictionary>
    </Application.Resources>
</Application>

こうして、ContentDialog を表示することろでは幅の設定はしない形にします。

// ContentDialog 自身の幅の設定はしない!
var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = string.Join(
        ", ", 
        Enumerable.Range(0, 100).Select(_ => Guid.NewGuid().ToString())),
    CloseButtonText = "Close",
};
await dialog.ShowAsync();

これで実行すると以下のようになります。いい感じにひろがってくれました。

でも、サイズの最大幅をもうちょっと小さくしたいんだけど…というケースもあると思います。その場合は ContentDialogContent に設定する部分で制御すると良さそうです。これまでの例では文字列を直接指定していましたが、ここにコントロールを設定して、そこでサイズに関する指定をします。

例えば TextBlock を使うと以下のような感じに設定できます。

// ContentDialog 自身の幅の設定はしない!
var dialog = new ContentDialog
{
    XamlRoot = Content.XamlRoot,
    Content = new TextBlock
    {
        // Content に設定する部分でサイズは制御する!
        // とりあえず最大幅は1000で折り返して表示してほしい!
        MaxWidth = 1000,
        TextWrapping = TextWrapping.Wrap,
        Text = string.Join(
            ", ",
            Enumerable.Range(0, 100).Select(_ => Guid.NewGuid().ToString())),
    },
    CloseButtonText = "Close",
};
await dialog.ShowAsync();

実行結果は以下のようになります。ちゃんと 1000 の幅までになっています。

普通は ContentDialogContent プロパティに設定するものは UserControl とかになることが多いと思うので、そこでいい感じのサイズ感になるように制御してあげるといいでしょう。

まとめ

App.xaml のリソースで <x:Double x:Key="ContentDialogMaxWidth">5000</x:Double> のように十分大きな値を設定した状態で ContentDialogContent に設定するコントロールでいい感じにサイズを制御してあげるのが良さそうです。

Microsoft (有志)

Discussion

kuremakurema

これなぁ…。
ContentDialogは標準のサイズが小さいだけじゃなく、UWPのAppWindowと相性悪いのよね。
同時に開くと落ちたり、XamlRoot指定必須だったり、リサイズ追従しなかったり。
でも代替がないから仕方ない。

Kazuki OtaKazuki Ota

@kurema
前の2つはわかったんですが、最後のリサイズはWindowサイズ変えたら、ContentDialogを常にWindowの幅の80%の幅に指定したいみたいなことですか?

kuremakurema

AppWindowでXamlRoot指定してAppWindow側に表示させるとウィンドウのリサイズを追従しないんですよね。
普通のウィンドウだったらもちろん機能するんですが。
多分XamlRootだけじゃなくて、イベント仕込むなり何かをしないといけないんだろうけれど。

image

Kazuki OtaKazuki Ota

普通のUWPのContentDialogは、そうなるんですか?
WinUI 3.0もプレビューの頃はそうなってましたけど、正式版ではなおってました

kuremakurema

普通のUWP環境では正常に動作します。幅は普通に狭いですが。
ただAppWindowというシングルスレッドで扱えるマルチウィンドウでは色々問題が出ます。
同時に開けないなどはドキュメントにも書いてあります。