LoginSignup
1
0

More than 3 years have passed since last update.

添付プロパティを使ってGridやStackPanelだけで表現できないレイアウトを実現する

Posted at

概要

WPFではStackPanelやGridといったパネルコントロールを使って、望みのレイアウトを表現します。
ほとんどのレイアウトはパネルコントロールの組み合わせで可能ですが、まれに出来ない場合もあります。
そのような場合に添付プロパティを使って、解決する方法を紹介します。

作りたいレイアウト

以下のように長い文字が入るTextBoxと別のコントロール、ここではButtonがいます。

このとき、以下のような動きをしたい、とします。
片方だけならそれぞれGridとStackPanelを使ってできますが、両方を同時に満たすことができません。

  • 長い文字が入ってもButtonが画面内に出ていかない、TextBoxの長さを制限したい
  • 短い文字の時はTextBoxを縮めてButtonを近くに置きたい

添付プロパティ

MaxWidth用のLimitMaxWidthMaxHeight用の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"

コードビハインドは使用していません。

MainWindow.xaml
<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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0