WPF StackPanelとScrollVIewerの不思議な動き
StackPanelとScrollViewerを組み合わせた時、
思った通りにScrollViewerが機能せずに引っ掛かることがある。
普通に動く場合
StackPanelをScrollViewerでラップすると、
画像のようにスクロール操作が出来るようになる。
機能しない場合
先の例とほとんど変わらないのだが、
ScrollViewerの親要素の大きさがAutoで指定されていると、
スクロールバーが見切れた状態になりスクロール操作が出来ない。
じゃあどうする?
ScrollViewerのサイズが特定出来るよう、Autoではなく*で高さを指定するとスクロール操作が出来るようになる。
なにが原因なのか?
はっきりとした理由は不明、なので予想だけ。
StackPanelは列挙する方向に対して無限長の領域をとると思われる。
ので、ScrollViewerでラップしてやるとStackPanelから返ってくる要求サイズは無限長となりScrollViewerの要求サイズも無限長となる。
本来であれば更に親の要素に要求サイズを渡したとき、
親の要素が具体的に決まっていればその大きさに合わせてScrollViewerのサイズも調整されるが
GridのAuto指定の場合だと子要素のサイズが採用されるのでScrollViewerとStackPanelのサイズは不定となる。
結果、画面には収まらないが要求された通りの描画が行われScrollViewerから見ても子要素が全部収まってるという判断がされるので、
スクロール操作は出来ないよね、という具合に判断されている。
MSDNによるとRowDefinition.Heightプロパティの既定値はstarなので、
最初のサンプルと最後のサンプルではWindowの高さに合わせた調整が行われ、
ScrollViewerのサイズもレイアウト時に調整されたのだろう。
つまり、ScrollViewerが自分の高さがわからないという状況にならなければ良いわけで、
ScrollViewerのMaxHeightプロパティに値を指定してもスクロールバーは動くようになる。
が、動的に配置を調整してくれるXAMLの強みが無くなってしまうのでこの方法は微妙だと思う。
StackOverFlowでも「ScrollViewerが上手く動かない」というトピックが散見され、
みんな同じとこで嵌ってる様子。
この辺りは仕様上の挙動と直感的な挙動が剥離してるよなぁ。。。
WPF 不明な型 ~ を作成できません。
XAML関係で引っ掛かりやすいところ。
XAMLの中で名前空間を指定する際に、同じアセンブリ内であればアセンブリ名を省略して記述することが出来る。
次の画像がアセンブリ名を省略したもの。
省略せずに記述したものは次の画像のようになる。
省略した方が記述が短いので良いのだが、
前者のディクショナリを外部のアセンブリから利用し、その名前空間内で宣言された型を生成しようとすると。
不明な型 ~ を作成できません。
と実行時に例外が出てしまう。
後者のようにアセンブリ名を省略しなければ例外は発生せず、ちゃんと動いてくれる。
XAMLはパースされた側が解決出来るか否かではなく、パースした側が解決出来るかどうかという問題ということだろうか???
(その割にはリソースディクショナリをマージする記述は相対パスだけでも大丈夫だったりするのだけど・・・)
WPF 外部ライブラリに宣言されているリソースディクショナリの使用方法
いつも書き方を忘れるのでメモ。
下の画像のようにプロジェクトResourceDictionaryServe内にリソースディクショナリMyResourceDictionaryがあったとして
これをResourceDictionaryClientで使いたいとなった場合の記述は以下の通り
ResourceDictionaryのSourceプロパティに
"/{アセンブリ名};component/{リソースディクショナリ名}"
と記述する。
WPFのVisibilityとIsVisibleの違い
twitterではぶつぶつ独り言を呟いているけど、
ブログの方は半年以上なにも書いてなかったのか・・・
ここしばらくWPFやC#で色々と痛い思いをしてるので、
忘れないように少しずつブログに吐き出す習慣をつけるようにしたい。
ソースやXAMLも載せた方が良いのだろうけど、
手間かけるとどうせ飽きるので適当に書きます。
で、掲題の話、
以前この違いをはっきり意識せずにコーディングしてて成大にバグったのでメモ
端的にいうと
Visibility→この要素の可視状態
IsVisible→この要素が表示されているか否か
ということ。
WPF ボタンのカスタマイズ方法概略
ボタン側のXAML
ボタンのXAML、Buttonクラスを継承して記述、コードビハインドは無し。
VSでユーザーコントロール(WPF)を追加して派生元をUserControlからButtonに変更したものを編集
<Button x:Class="WpfApp1.CustomButton" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" OverridesDefaultStyle="True" FocusVisualStyle="{x:Null}" > <Button.Template> <ControlTemplate TargetType="Button"> <Grid> <Border x:Name="ButtonVisual" BorderBrush="DimGray" BorderThickness="2" Background="AliceBlue" > <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" /> </Border> <Border x:Name="MaskOnPressed" Background="Black" Opacity="0.1" Visibility="Hidden" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsFocused" Value="true"> <Setter TargetName="ButtonVisual" Property="BorderBrush" Value="MidnightBlue"/> </Trigger> <Trigger Property="IsMouseOver" Value="true"> <Setter TargetName="ButtonVisual" Property="Background" Value="Lavender"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Opacity" Value="0.5"/> </Trigger> <Trigger Property="IsPressed" Value="true"> <Setter TargetName="MaskOnPressed" Property="Visibility" Value="Visible"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Button.Template> </Button>
画面側のXAML
ボタンを画面に貼っつけたXAML、こちらもコードビハインドなし。
<Window x:Class="WpfApp1.MainWindow" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Canvas> <local:CustomButton Canvas.Left="10" Canvas.Top="10" Width="100" Height="20" Content="ボタン1" /> <local:CustomButton Canvas.Left="10" Canvas.Top="40" Width="100" Height="20" Content="ボタン2" /> <local:CustomButton Canvas.Left="10" Canvas.Top="70" Width="100" Height="20" Content="ボタン3" IsEnabled="False" /> </Canvas> </Window>
実行時イメージ
上から順に、
フォーカス取得中
フォーカス無しの表示
Disable(IsEnabled=false)の表示
ポイント
標準スタイルの無効化
・OverridesDefaultStyle=”true”で標準のスタイルを読み込まないように
・FocusVisualStyle="{x:Null}"でフォーカス取得時スタイルを初期化
(フォーカス取得時に点線が表示されるやつ。)
トリガーで実現しているもの
・フォーカス時に外枠の色を濃い目に変更
・マウスオーバー時に塗りつぶし色を濃い目に変更
・Disableの時、全体を半透明にして使えないっぽい外観に
・押下時、半透明のフィルタを被せて操作に対するレスポンスを表現
WPF 描画の練習 マル印
前回の記事に引き続き、WPFの描画周りを練習
前回の記事はこちら↓
nomoredeathmarch.hatenablog.com
前回はバツ印を作ったので今回はマル印を作ってみました。
まだ簡単・・・
イメージ
XAML
<UserControl x:Class="WpfApp1.UserControl2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Canvas Height="100" Width="100" Background="Aqua" > <Path Stroke="Black" > <Path.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Tomato" Offset="0"/> <GradientStop Color="Red" Offset="0.5"/> <GradientStop Color="Crimson" Offset="0.7"/> </LinearGradientBrush> </Path.Fill> <Path.Data> <CombinedGeometry GeometryCombineMode="Xor" > <CombinedGeometry.Geometry1> <EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50"/> </CombinedGeometry.Geometry1> <CombinedGeometry.Geometry2> <EllipseGeometry Center="50,50" RadiusX="30" RadiusY="30"/> </CombinedGeometry.Geometry2> </CombinedGeometry> </Path.Data> </Path> </Canvas> </UserControl>
ポイント
・半径が違う円を重ねて合成
・GeometryCombineModeはXorでGeometry2の領域を描画しない
ジオメトリの使い方、良いサンプルないかなぁってネットで検索したりしてたのですが、
手元にあるエッセンシャルWPFの204ページ辺りにしっかり書いてありました。
エッセンシャルWPF:Windows Presentation Foundation (Programmer's SELECTION)
- 作者: Chris Anderson,星睦
- 出版社/メーカー: 翔泳社
- 発売日: 2007/10/31
- メディア: 大型本
- 購入: 6人 クリック: 128回
- この商品を含むブログ (32件) を見る