添付プロパティを使ってGridやStackPanelだけで表現できないレイアウトを実現する
概要
WPFではStackPanelやGridといったパネルコントロールを使って、望みのレイアウトを表現します。
ほとんどのレイアウトはパネルコントロールの組み合わせで可能ですが、まれに出来ない場合もあります。
そのような場合に添付プロパティを使って、解決する方法を紹介します。
作りたいレイアウト
以下のように長い文字が入るTextBoxと別のコントロール、ここではButtonがいます。
このとき、以下のような動きをしたい、とします。
片方だけならそれぞれGridとStackPanelを使ってできますが、両方を同時に満たすことができません。
- 長い文字が入ってもButtonが画面内に出ていかない、TextBoxの長さを制限したい
- 短い文字の時はTextBoxを縮めてButtonを近くに置きたい
添付プロパティ
MaxWidth
用のLimitMaxWidth
とMaxHeight
用のLimitMaxHeight
の2つのフォーマットを指定できる添付プロパティが定義されています。
class LimitSizeHelper
{
#region LimitMaxHeight添付プロパティ
public static double GetLimitMaxHeight(DependencyObject obj) => (double)obj.GetValue(LimitMaxHeightProperty);
public static void SetLimitMaxHeight(DependencyObject obj, double value) => obj.SetValue(LimitMaxHeightProperty, value);
public static readonly DependencyProperty LimitMaxHeightProperty =
DependencyProperty.RegisterAttached("LimitMaxHeight", typeof(double), typeof(LimitSizeHelper),
new PropertyMetadata(1d, (d, e) => AddLimitMaxSize(d, e, false)));
#endregion
#region LimitMaxWidth添付プロパティ
public static double GetLimitMaxWidth(DependencyObject obj) => (double)obj.GetValue(LimitMaxWidthProperty);
public static void SetLimitMaxWidth(DependencyObject obj, double value) => obj.SetValue(LimitMaxWidthProperty, value);
public static readonly DependencyProperty LimitMaxWidthProperty =
DependencyProperty.RegisterAttached("LimitMaxWidth", typeof(double), typeof(LimitSizeHelper),
new PropertyMetadata(-1d, (d, e) => AddLimitMaxSize(d, e, true)));
#endregion
private static void AddLimitMaxSize(DependencyObject d, DependencyPropertyChangedEventArgs e, bool isWidth)
{
if (d is FrameworkElement targetObj
&& targetObj.Parent is Panel panel
&& e.NewValue is double newValue && newValue > 0)
{
panel.SizeChanged += (o, _) =>
Parent_SizeChanged(targetObj, panel, isWidth, newValue);
}
}
private static void Parent_SizeChanged(FrameworkElement targetObj, Panel panel, bool isWidth, double ratio)
{
var otherSumSize = panel.Children
.Cast<FrameworkElement>()
.Where(x => x != targetObj)
.Sum(x => isWidth ? x.ActualWidth : x.ActualHeight);
double maxSize = ((isWidth ? panel.ActualWidth : panel.ActualHeight) - otherSumSize) * ratio;
if (isWidth)
targetObj.MaxWidth = maxSize;
else
targetObj.MaxHeight = maxSize;
}
}
使用方法
XAML上で親コントロールに対する比率を指定します。
local:LimitSizeHelper.LimitMaxWidth="0.99"
コードビハインドは使用していません。
<Window
x:Class="LimitSizeControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LimitSizeControl"
Width="300" Height="300">
<!-- Width制限 -->
<StackPanel
Margin="10"
Background="LightSlateGray"
Orientation="Horizontal">
<TextBox
local:LimitSizeHelper.LimitMaxWidth="0.99"
Text="LLLLLLLLLLLLLLLOOOOOOOOOOONNNNNNNNNGGGGGG"
TextWrapping="Wrap" />
<Button Content="BUTTON" />
</StackPanel>
<!-- Height制限 -->
<!--<StackPanel Margin="10" Background="LightSlateGray">
<TextBox
Width="50"
local:LimitSizeHelper.LimitMaxHeight="0.99"
Text="LLLLLLLLLLLLLLLLLLLLLLOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNGHHHHHHHHHHHHHHHHGGGGGGGGG"
TextWrapping="Wrap" />
<Button Content="BUTTON" />
</StackPanel>-->
</Window>
環境
VisualStudio 2019 Version 16.8.4
.NET 5
C#9
参考
https://qiita.com/YSRKEN/items/686068a359866f21f956
https://www.atmarkit.co.jp/ait/articles/1011/30/news116_2.html
Author And Source
この問題について(添付プロパティを使ってGridやStackPanelだけで表現できないレイアウトを実現する), 我々は、より多くの情報をここで見つけました https://qiita.com/soi/items/5235a407064b393fb47e著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .