1

カスタム プロパティで指定された色で始まり、ハードコードされた色で終わる、背景のグラデーションを表示する Button コントロールを作成しようとしています。これは簡単なコントロール テンプレートのように思えますが、機能させることができません。

Color依存関係プロパティを持つサブクラス化された「ボタン」 :

public class GradientButton : Button
{
    public Color BackgroundColor
    {
        get { return (Color)GetValue(BackgroundColorProperty); }
        set { SetValue(BackgroundColorProperty, value); }
    }

    public static readonly DependencyProperty BackgroundColorProperty =
        DependencyProperty.Register("BackgroundColor", typeof(Color), typeof(GradientButton), new PropertyMetadata((sender, args) => {
            System.Diagnostics.Debug.WriteLine("Set bg col");
        }));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(GradientButton), null);
    public GradientButton()
        : base()
    {
        this.DefaultStyleKey = typeof(GradientButton);
    }
}

BackgroundColorDPを使用して背景のグラデーションを設定するコントロール テンプレート:

<Style TargetType="custom:GradientButton">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Setter Property="Width" Value="200" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="custom:GradientButton">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                            <GradientStop Color="{TemplateBinding BackgroundColor}" Offset="0" />
                            <GradientStop Color="Gray" Offset="1" />
                        </LinearGradientBrush>
                    </Grid.Background>

                    <TextBlock Text="{TemplateBinding Text}" />
                    <TextBlock Text="{TemplateBinding BackgroundColor}" HorizontalAlignment="Right" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

次のようなコントロールを使用する場合:

<custom:GradientButton Text="Foo" BackgroundColor="#FF0000" /> 

次に、赤から灰色へのグラデーションの背景を持つボタンが表示されることを期待しています。代わりに、グラデーションの灰色の部分のみが表示されます。

コントロールに背景の赤い部分が表示されない

私が見逃している痛々しいほど明らかなことは何ですか?


強調のために編集:

  1. DP / TemplateBindingが実際にコーシャであることを証明するために、「テキスト」DPを追加しました。
  2. テキストブロック内のテキストとしても、「BackgroundColor」を表示できないことに注意してください。ただし、実際にはコントロールに設定されていることをデバッガーで確認しました。
4

3 に答える 3

1

問題ない、

最初の問題は、グラデーションを宣言する方法です。現在の方法では、上半分に赤の実線 (または指定された色) が表示され、下半分に灰色の実線が表示されます。このようなものが必要な場合は、それが残りの作業を行います。

<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
     <GradientStop Color="Red" Offset="0"/>
     <GradientStop Color="Gray" Offset="1"/>
</LinearGradientBrush>

また、これを自分で簡単にし、このような目的のために既に存在するプロパティを利用するだけで、追加のコードは必要ありません。プロパティのようにTag(個人的には、インスタンスに応じてさまざまな目的のためにあらゆる種類のがらくたを詰め込みます。したがって、このようなものは、追加の依存関係宣言を必要とせずに十分です(「BackgroundColor」と呼ばれる本当に重要でない限り) ;

<Style TargetType="custom:GradientButton">
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="VerticalAlignment" Value="Top" />
    <Setter Property="Width" Value="200" />
    <Setter Property="Tag" Value="Red"/><!-- For the sake of having a default -->

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="custom:GradientButton">
                <Grid>
                    <Grid.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                             <GradientStop Color="{TemplateBinding Tag}" Offset="0"/>
                             <GradientStop Color="Gray" Offset="1"/>
                        </LinearGradientBrush>
                    </Grid.Background>

                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

これでうまくいくはずです。これが役立つことを願っています。:)

于 2013-07-24T21:02:59.037 に答える
1

回避策を発見しました: の代わりにバインディングTemplateBindingを使用するRelativeSourceと、ボタンは期待どおりにレンダリングされます。

Color="{Binding RelativeSource={RelativeSource AncestorType=custom:GradientButton},Path=BackgroundColor}"

もちろん、これはほとんど意味がありません。私はこれがバグであると確信しています (または、人間が知ることを意図していないことの少なくとも 1 つ)。

于 2013-07-24T21:29:10.507 に答える
1

混乱させてすみません。私の答えは正しくありません。ここでの問題は TemplateBinding です。TemplateBinding はコンパイル時の軽量バインディングですが、TemplatedParent の使用は実行時に発生します。したがって、TemplateBinding にはいくつかの制限があり、そのうちの 1 つは Freezable にバインドできません。できることは、代わりに従来のテンプレート化された親を使用することです。

<GradientStop Color="{Binding Path=BackgroundColor, RelativeSource={RelativeSource TemplatedParent}}" Offset="0" />

http://blogs.msdn.com/b/liviuc/archive/2009/12/14/wpf-templatebinding-vs-relativesource-templatedparent.aspxを参照できます。

「コンパイラまたはランタイムが何らかのエラーをスローすると思うかもしれませんが、明らかにそうではありません。」

良い点です。出力ウィンドウにもバインディング エラーは表示されませんでした。ただし、Snoop を使用して Color プロパティを調べたところ、まさに期待どおりの結果が得られました。

System.Windows.Data エラー: 2: ターゲット要素の管理 FrameworkElement または FrameworkContentElement が見つかりません。BindingExpression:Path=BackgroundColor; DataItem=null; ターゲット要素は 'GradientStop' (HashCode=4605357) です。ターゲット プロパティは 'Color' (タイプ 'Color')

于 2013-07-24T21:23:16.133 に答える