くうと徒然なるままに

モバイルアプリを作りながらバックエンドも作っています。

WPF の UserControl で コントロールの高さと幅を取得する

やりかた

WPF アプリに UserControl を追加します、以下のような コードを高さを幅を表示するために追加しておきます。

具体的には、 ActualHeight メソッドと、 ActualWidth メソッドを利用することで取得できます。

Xaml コード

<StackPanel>
    <TextBlock Name="Height"></TextBlock>
    <TextBlock Name="Width"></TextBlock>
</StackPanel>

CSharp コード

public UserControl1()
{
    InitializeComponent();

    Height.Text = ActualHeight.ToString();
    Width.Text = ActualWidth.ToString();
}

しかし、取得できない

2つ並べたテキストブロックに UserControl の高さと幅が表示されることが想定されますが、実際には、表示されていません。

解決策

非同期 で ActualHeight メソッドと、 ActualWidth メソッド を実行する

この問題は、一見同期的に実行されるように見えるメソッドが非同期で実行されるところに問題があります。 具体的には、以下のメソッドは、 Xaml を解析したり、コントロールを配置したりするメソッドです。このメソッドが非同期的に実行されます。

InitializeComponent()

そのため、

InitializeComponent() が呼び出されたすぐ後に、 UserControl の高さと幅を取得しても、 0 になってしまいます。

ということで、 今回は、 Dispatcher.BeginInvoke() メソッドを使って解決していきます。

CSharp コード

 public UserControl1()
        {
            InitializeComponent();

            Dispatcher.BeginInvoke(new Action(() =>
            {
                Height.Text = ActualHeight.ToString();
                Width.Text = ActualWidth.ToString();
            }),
            DispatcherPriority.Loaded);
        }

実行結果

できました。

解決策②

実際に使うときは、ウィンドウの大きさを変えたときにも対応できるようにしたいといけないため、対応できるコードも置いておきます。

SizeChanged += (sender, args) =>
{
    Height.Text = ActualHeight.ToString();
    Width.Text = ActualWidth.ToString();
};

実行結果