none
Expanderの角の丸さを変えたい RRS feed

  • 質問

  • WPF初心者です。

    Expanderの角の丸さを変えるにはどうしたら良いでしょうか?

    BorderのCornerRadiusのようなものがあれば一発でしょうが、見つかりませんでした。

    2015年8月3日 12:39

回答

  • WPFでは外見を変更したいときに望むようなプロパティが無ければテンプレートを変更してやると好きなように外見を変更することができます。
    たとえば、エクスパンダ―だと「エクスパンダ―のスタイルとテンプレート」にあるようなものです。
    テンプレートをエクスパンダ―に適用するには「ControlTemplate の作成による既存のコントロールの外観のカスタマイズ」にあるようなことを理解する必要があります。

    とはいえ、エクスパンダ―はトリガーやステートも理解していないと1から作るのは大変です。
    それは初心者には難しいので、デザイナでにExpanderを配置して、Expanderを右クリックしたメニュー->テンプレートの編集->コピーして編集 とすると、テンプレートを編集しやすいようにリソースを作ってくれます。(VS2012以降からだったかな)
    出てきたテンプレートでBorderを探して、CornerRadiusを適用すれば角の丸めができます。

    それでも難しそうなら以下のコードで

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Expander ExpandDirection="Down" VerticalAlignment="Top" HorizontalAlignment="Stretch" Header="Expander"
                      Loaded="Expander_Loaded" Expanded="Expander_ExpandChanged" Collapsed="Expander_ExpandChanged"
                      Background="LightBlue"  >
                <StackPanel Orientation="Horizontal" Margin="20,0,20,0">
                    <Button Width="20" Height="20" />
                    <Button Width="20" Height="20" />
                </StackPanel>
            </Expander>
        </Grid>
    </Window>
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Expander_Loaded(object sender, RoutedEventArgs e)
            {
                var exp = (Expander)sender;
                Border b = FindChild<Border>(exp, exp);
                b.CornerRadius = new CornerRadius(0, 0, 0, 0);
            }
            private void Expander_ExpandChanged(object sender, RoutedEventArgs e)
            {
                //Expanderの最初にあるBorderを見つけて、CornerRadiusを適用する
                var exp = (Expander)sender;
                Border b = FindChild<Border>(exp, exp);
    
                if (exp.IsExpanded)
                {
                    switch (exp.ExpandDirection)
                    {
                    case ExpandDirection.Left:
                        b.CornerRadius = new CornerRadius(20, 0, 0, 20);
                        break;
                    case ExpandDirection.Right:
                        b.CornerRadius = new CornerRadius(0, 20, 20, 0);
                        break;
                    case ExpandDirection.Down:
                        b.CornerRadius = new CornerRadius(0, 0, 20, 20);
                        break;
                    case ExpandDirection.Up:
                        b.CornerRadius = new CornerRadius(20, 20, 0, 0);
                        break;
                    }
                }
                else
                {
                    b.CornerRadius = new CornerRadius(0, 0, 0, 0);
                }
            }
    
            /// <summary>
            /// 親から子をたどって指定した型で、親のテンプレートによって作られたDependencyObjectを見つける
            /// </summary>
            /// <typeparam name="T">見つけたい型</typeparam>
            /// <param name="d">探索対象</param>
            /// <param name="templateParent">大本の親</param>
            /// <returns>見つかったDependencyObject</returns>
            private static T FindChild<T>(DependencyObject d, DependencyObject templateParent) where T : FrameworkElement
            {
                FrameworkElement fe = d as FrameworkElement;
                if (fe!= null && fe.TemplatedParent != templateParent && d != templateParent)
                {
                    return null;
                }
                T t = d as T;
                if (t != null)
                {
                    return t;
                }
                int count = VisualTreeHelper.GetChildrenCount(d);
                for (int i = 0; i < count; i++)
                {
                    var child = VisualTreeHelper.GetChild(d, i);
                    t = FindChild<T>(child, templateParent);
                    if (t != null)
                    {
                        return t;
                    }
                }
                return null;
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2015年8月3日 23:55 コードが壊れてた
    • 回答としてマーク C.John 2015年8月4日 14:30
    2015年8月3日 15:54
  • コントロールテンプレートを編集する必要があります。

    Visual Studio2015(2013でも)なら、ソリューションエクスプローラーからxamlを右クリック→「Blendでデザイン」でBlendを開き、

    オブジェクトウインドウからExpandarを右クリック→「テンプレートの編集」→「コピーして編集」。

    Styleが追加されるので、"ExpanderStyle1"のControlTemplate内のBorderのCornerRadiusを好きなように編集すればOkです。

    <Style x:Key="ExpanderStyle1" TargetType="{x:Type Expander}"> 
    
    <!--中略-->
    
    <ControlTemplate TargetType="{x:Type Expander}">
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
                         




    • 回答としてマーク C.John 2015年8月4日 14:31
    2015年8月3日 15:43

すべての返信

  • コントロールテンプレートを編集する必要があります。

    Visual Studio2015(2013でも)なら、ソリューションエクスプローラーからxamlを右クリック→「Blendでデザイン」でBlendを開き、

    オブジェクトウインドウからExpandarを右クリック→「テンプレートの編集」→「コピーして編集」。

    Styleが追加されるので、"ExpanderStyle1"のControlTemplate内のBorderのCornerRadiusを好きなように編集すればOkです。

    <Style x:Key="ExpanderStyle1" TargetType="{x:Type Expander}"> 
    
    <!--中略-->
    
    <ControlTemplate TargetType="{x:Type Expander}">
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="true">
                         




    • 回答としてマーク C.John 2015年8月4日 14:31
    2015年8月3日 15:43
  • WPFでは外見を変更したいときに望むようなプロパティが無ければテンプレートを変更してやると好きなように外見を変更することができます。
    たとえば、エクスパンダ―だと「エクスパンダ―のスタイルとテンプレート」にあるようなものです。
    テンプレートをエクスパンダ―に適用するには「ControlTemplate の作成による既存のコントロールの外観のカスタマイズ」にあるようなことを理解する必要があります。

    とはいえ、エクスパンダ―はトリガーやステートも理解していないと1から作るのは大変です。
    それは初心者には難しいので、デザイナでにExpanderを配置して、Expanderを右クリックしたメニュー->テンプレートの編集->コピーして編集 とすると、テンプレートを編集しやすいようにリソースを作ってくれます。(VS2012以降からだったかな)
    出てきたテンプレートでBorderを探して、CornerRadiusを適用すれば角の丸めができます。

    それでも難しそうなら以下のコードで

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Expander ExpandDirection="Down" VerticalAlignment="Top" HorizontalAlignment="Stretch" Header="Expander"
                      Loaded="Expander_Loaded" Expanded="Expander_ExpandChanged" Collapsed="Expander_ExpandChanged"
                      Background="LightBlue"  >
                <StackPanel Orientation="Horizontal" Margin="20,0,20,0">
                    <Button Width="20" Height="20" />
                    <Button Width="20" Height="20" />
                </StackPanel>
            </Expander>
        </Grid>
    </Window>
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Expander_Loaded(object sender, RoutedEventArgs e)
            {
                var exp = (Expander)sender;
                Border b = FindChild<Border>(exp, exp);
                b.CornerRadius = new CornerRadius(0, 0, 0, 0);
            }
            private void Expander_ExpandChanged(object sender, RoutedEventArgs e)
            {
                //Expanderの最初にあるBorderを見つけて、CornerRadiusを適用する
                var exp = (Expander)sender;
                Border b = FindChild<Border>(exp, exp);
    
                if (exp.IsExpanded)
                {
                    switch (exp.ExpandDirection)
                    {
                    case ExpandDirection.Left:
                        b.CornerRadius = new CornerRadius(20, 0, 0, 20);
                        break;
                    case ExpandDirection.Right:
                        b.CornerRadius = new CornerRadius(0, 20, 20, 0);
                        break;
                    case ExpandDirection.Down:
                        b.CornerRadius = new CornerRadius(0, 0, 20, 20);
                        break;
                    case ExpandDirection.Up:
                        b.CornerRadius = new CornerRadius(20, 20, 0, 0);
                        break;
                    }
                }
                else
                {
                    b.CornerRadius = new CornerRadius(0, 0, 0, 0);
                }
            }
    
            /// <summary>
            /// 親から子をたどって指定した型で、親のテンプレートによって作られたDependencyObjectを見つける
            /// </summary>
            /// <typeparam name="T">見つけたい型</typeparam>
            /// <param name="d">探索対象</param>
            /// <param name="templateParent">大本の親</param>
            /// <returns>見つかったDependencyObject</returns>
            private static T FindChild<T>(DependencyObject d, DependencyObject templateParent) where T : FrameworkElement
            {
                FrameworkElement fe = d as FrameworkElement;
                if (fe!= null && fe.TemplatedParent != templateParent && d != templateParent)
                {
                    return null;
                }
                T t = d as T;
                if (t != null)
                {
                    return t;
                }
                int count = VisualTreeHelper.GetChildrenCount(d);
                for (int i = 0; i < count; i++)
                {
                    var child = VisualTreeHelper.GetChild(d, i);
                    t = FindChild<T>(child, templateParent);
                    if (t != null)
                    {
                        return t;
                    }
                }
                return null;
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2015年8月3日 23:55 コードが壊れてた
    • 回答としてマーク C.John 2015年8月4日 14:30
    2015年8月3日 15:54
  • WPFでは外見を変更したいときに望むようなプロパティが無ければテンプレートを変更してやると好きなように外見を変更することができます。
    たとえば、エクスパンダ―だと「エクスパンダ―のスタイルとテンプレート」にあるようなものです。
    テンプレートをエクスパンダ―に適用するには「ControlTemplate の作成による既存のコントロールの外観のカスタマイズ」にあるようなことを理解する必要があります。

    教えていただいたリンクを読んでみましたが、理解度30%くらいだったので、また理解が進んでからもう一度見たいと思います。

    デザイナでにExpanderを配置して、Expanderを右クリックしたメニュー->テンプレートの編集->コピーして編集

    このやり方で実現できました。

    ありがとうございます。

    2015年8月4日 14:30
  • 最近はBlend無くてもコントロールテンプレート編集できるようになったんですねえ。

    やっぱりMSDNフォーラムは勉強になる

    2015年8月5日 7:27