No more Death March

あるSEのチラシの裏 C# WPF

WPF StackPanelとScrollVIewerの不思議な動き

StackPanelとScrollViewerを組み合わせた時、
思った通りにScrollViewerが機能せずに引っ掛かることがある。

普通に動く場合

f:id:nomoredeathmarch:20190120174203p:plain

StackPanelをScrollViewerでラップすると、
画像のようにスクロール操作が出来るようになる。

機能しない場合

f:id:nomoredeathmarch:20190120174207p:plain

先の例とほとんど変わらないのだが、
ScrollViewerの親要素の大きさがAutoで指定されていると、
スクロールバーが見切れた状態になりスクロール操作が出来ない。

じゃあどうする?

f:id:nomoredeathmarch:20190120174211p:plain

ScrollViewerのサイズが特定出来るよう、Autoではなく*で高さを指定するとスクロール操作が出来るようになる。

なにが原因なのか?

はっきりとした理由は不明、なので予想だけ。

StackPanelは列挙する方向に対して無限長の領域をとると思われる。
ので、ScrollViewerでラップしてやるとStackPanelから返ってくる要求サイズは無限長となりScrollViewerの要求サイズも無限長となる。

本来であれば更に親の要素に要求サイズを渡したとき、
親の要素が具体的に決まっていればその大きさに合わせてScrollViewerのサイズも調整されるが
GridのAuto指定の場合だと子要素のサイズが採用されるのでScrollViewerとStackPanelのサイズは不定となる。

結果、画面には収まらないが要求された通りの描画が行われScrollViewerから見ても子要素が全部収まってるという判断がされるので、
スクロール操作は出来ないよね、という具合に判断されている。

MSDNによるとRowDefinition.Heightプロパティの既定値はstarなので、
最初のサンプルと最後のサンプルではWindowの高さに合わせた調整が行われ、
ScrollViewerのサイズもレイアウト時に調整されたのだろう。

docs.microsoft.com

つまり、ScrollViewerが自分の高さがわからないという状況にならなければ良いわけで、
ScrollViewerのMaxHeightプロパティに値を指定してもスクロールバーは動くようになる。
が、動的に配置を調整してくれるXAMLの強みが無くなってしまうのでこの方法は微妙だと思う。


StackOverFlowでも「ScrollViewerが上手く動かない」というトピックが散見され、
みんな同じとこで嵌ってる様子。

この辺りは仕様上の挙動と直感的な挙動が剥離してるよなぁ。。。