WrapPanelでのWPFコントロール幅の同期
-
10-07-2019 - |
質問
この場合
<WrapPanel>
<CheckBox>Really long name</CheckBox>
<CheckBox>Short</CheckBox>
<CheckBox>Longer again</CheckBox>
<CheckBox>Foo</CheckBox>
<Slider MinWidth="200" />
</WrapPanel>
WrapPanel内のすべてのCheckBoxを同じ幅にしたい。
次のものを追加すると、目的の効果がほぼ達成されます
<WrapPanel.Resources>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="MinWidth" Value="75" />
</Style>
</WrapPanel.Resources>
ただし、特定の幅をハードコードしたくはありません。むしろ、最大のCheckBoxに幅を設定させます(幅&gt; 75の場合、上記も失敗します)。
スライダーは独立しており、CheckBoxesよりも大きくする必要があります。
ハードコーディングされた列数が必要ないため、グリッド(IsSharedSizeScopeを使用)は使用しません。
この記事は興味深い解決策を示していますが、カスタムコントロールを作成したり、C#コードを使用したりせずに問題を解決します。
これを行う最良の方法は何ですか?できればXAMLのみですか?
解決
私はもともとIsSharedSizeGroupを使用してこれを見ましたが、アイテムを明示的にラップする代わりに物事に動的に適用することで障害になりました。この場合、コードまたは別のコードベースのソリューションでAttachedPropertyを作成すると、長期的にはXAMLのみのアプローチよりも優れている場合があります。ただし、純粋なXAMLソリューションを作成するには、 ColumnDefinitionのSharedSizeGroup プロパティを使用して各要素のサイズを共有し、set WrapPanelのIsSharedSizeScope プロパティ。これにより、同じSharedSizeGroupを持つWrapPanelのすべてのコンテンツが、列の幅と行の高さを共有します。現在XAMLにはないがWrapPanelに追加されるComboBoxesおよび場合によってはComboBoxesをラップするには、スタイルを作成し、ComboBoxを再テンプレートしてグリッドで基本的にラップします。
<WrapPanel Grid.IsSharedSizeScope="True">
<WrapPanel.Resources>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid Background="LightBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="WrapPannelGroup" />
</Grid.ColumnDefinitions>
<CheckBox Style="{x:Null}"
IsChecked="{TemplateBinding IsChecked}">
<!--Other TemplateBindings-->
<CheckBox.Content>
<ContentPresenter />
</CheckBox.Content>
</CheckBox>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</WrapPanel.Resources>
<CheckBox>Really long name</CheckBox>
<CheckBox>Short</CheckBox>
<CheckBox IsChecked="True">Longer again</CheckBox>
<CheckBox>Foo</CheckBox>
<Slider MinWidth="200" />
</WrapPanel>
ここでは、WrapPannel内にスタイルのないすべてのCheckBoxを再テンプレート化して、代わりにグリッドに囲まれたCheckBoxにします。ただし、このため、維持するすべてのCheckBoxesプロパティを再バインドする必要があります。それは面倒になりますが、純粋なXAMLアプローチも可能にします。
他のヒント
必要な作業を行うプロパティまたはコンバーターを追加し、各列の幅をそれにバインドできます。プロパティまたはコンバーターは、アイテムのリスト全体にアクセスし、最も広いものを見つけて、すべての要素に必要な幅を返すことができます。
これを行う最良の方法は、投稿した記事のようなCustomControlを使用することです。
あなたが遭遇した解決策は、アイテムのリストを反復処理し、測定段階で最大幅を見つける必要があります。
あらゆる種類のXAML専用の回答をOOTB(IsSharedSizeScopeなど)で提供するか、何らかのマルチバインディングを利用してアイテムをリンクする必要があります。したがって、あらゆる種類のXAML回答はマークアップでいっぱいになり、より冗長になります(そしてエレガントではなくなります)。
あなたが投稿したCodeProjectの記事に私が見る唯一の変更は、「ターンオフ」機能を追加することです。特定の要素(スライダーなど)の考慮。これは、追加の添付プロパティとして実行できます。