trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

LineにLinearGradientBrushを適用したものをCustomControlとして作る

目次

  1. WPFのCustomControlでアニメーション-概要
  2. LineにLinearGradientBrushを適用したものをCustomControlとして作る←ここ
  3. Storyboardを作成する(XAML)
  4. Storyboardを切り替える(XAML)
  5. Storyboardを切り替える(Code Behind)
  6. Storyboardを作成する(Code Behind)

ここでやること

LineにLinearGradientBrushを適用したものをCustomControlとして作る。

f:id:trsing:20210228180614p:plain

作成

準備

ソリューションエクスプローラを右クリック→追加→新しい項目→カスタム コントロール(WPF)

これで必要なファイル(.csとGeneric.xaml)が作成される。

.cs

線の両端(X1,X2,Y1,Y2)とGradient用に二色(LeftColor,RightColor)を受け取るために依存関係プロパティを作成。
※依存プロパティ作成のスニペット(propdp)が登録されているので使うと便利。

依存プロパティを作成しただけなのでコードは略

Generic.xaml

  • Lineに受け取った端点(X1,X2,Y1,Y2)をBind。
  • Line.StrokeにLinearGradientBrushを設定。
  • LinearGradientBrushに受け取った二色(LeftColor,RightColor)をBind。
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:GradientLineTest.Controls"
    >

    <Style TargetType="{x:Type local:GradientLineControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:GradientLineControl}">
                    <Line X1="{TemplateBinding X1}" Y1="{TemplateBinding Y1}"
                          X2="{TemplateBinding X2}" Y2="{TemplateBinding Y2}"
                          StrokeThickness="10"
                          >
                        <Line.Stroke>
                            <LinearGradientBrush StartPoint="0.0,0.5" EndPoint="1.0,0.5">
                                <GradientStop Color="{Binding LeftColor,RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0"/>
                                <GradientStop Color="{Binding RightColor,RelativeSource={RelativeSource TemplatedParent}}" Offset="1"/>
                            </LinearGradientBrush>
                        </Line.Stroke>
                    </Line>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

気になった点

二点

  • TemplateBindingって何?
  • GradientStopでTemplateBindingではなくBindingつかってるのはなぜ?

調べた結果

TemplateBinding hogeBinding hoge, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWayの特殊ケース。

TemplateBindingはFreezableなものには使えない。BrushはFreezableなのでGradientStopではBindingを使用している。

他、暗黙の変換がされないなどもあるので使うときは注意。

参考

A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}.

https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/templatebinding-markup-extension?view=netframeworkdesktop-4.8

TemplateBinding - More limiting than using regular Binding
* More efficient than a Binding but it has less functionality * Only works inside a ControlTemplate's visual tree * Doesn't work with properties on Freezables * Doesn't work within a ControlTemplate's Trigger Provides a shortcut in setting properties(not as verbose),e.g. {TemplateBinding targetProperty}

https://stackoverflow.com/questions/1131222/wpf-templatebinding-vs-relativesource-templatedparent

  • TemplateBinding does not support implicit type conversion in the way that a normal binding does (ie, string-to-ImageSource)

https://stackoverflow.com/questions/22134281/templatebinding-fails-when-the-target-is-an-imagebrush-imagesource