6

私は現在WPFを学習しようとしており、スタイルを使用してデフォルトの.Netコントロールの外観を変えることを検討しています。以下のコードはすべてWPFマークアップですが、C#を優先言語として使用しています。

私は今日、新しいテーマでgmailをセットアップし(下の画像を参照)、したがって、自分自身に挑戦を設定しました。これは、WPFで実行できます。

新しいGMailボタン

私が何とか達成したのはSpam、コントロールテンプレートとトリガーを備えたスタイルを使用して中央のボタンを作成することです。

右ボタンと左ボタンは非常に似ていますが、違いは2つだけです。左側または右側のコーナー半径は1、マージンは15ですが、中央のボタンでは両方とも0に設定されています。

質問!

Q1。スタイル全体をコピーしてこれら2つの属性だけを変更するのではなく、ある種の継承を介して行うことができます。左右のボタンは既存のスタイルに基づいていますが、これら2つの視覚的な変更を行います。新しいスタイルを作成するときにすでにBasedOnプロパティを試しましたが、必要な属性を編集できませんでした。

Q2。スタイルは、WPFでこの問題に対処するための正しい方法です。WinFormsでは、列挙型にリンクされた表示プロパティを持つカスタムコントロールを作成することを検討します。つまり、ボタンをクリックすると、スタイルオプションが左、中央、右になります。

Q3。最後まで最も難しい質問。それを作ることは可能ですか、それでボタンに私のスタイルが適用されている場合。次に、背景色を青に設定すると。次に、ボタンはグラデーションを維持しますが、オフホワイトではなく、青の色合いになります。つまり、背景の線形グラデーションブラシは、ボタンに適用された背景色を上書きするのではなく、に基づいています。または、これらに個別のスタイルを定義する必要がありますか?私は個人的に、これが達成できるという背後にあるタイプのコード、つまりWPFマークアップの単一のブラシからグラデーションブラシを作成することなしにはわかりません。

つまり、青いボタンと灰色/通常のボタンの下にあるボタン

Googleボタン2

私のスタイル

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="#F1F1F1" Offset="0"/>
                    <GradientStop Color="#F5F5F5" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Foreground" Value="#666666"/>
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="FontSize" Value="13"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border Name="dropShadowBorder"
                        BorderThickness="0,0,0,1"
                        CornerRadius="1"
                        >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#00000000"/>
                        </Border.BorderBrush>
                    <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="0" 
                    Background="{TemplateBinding Background}">
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" TargetName="border">
                                <Setter.Value>
                                    <SolidColorBrush Color="#939393"/>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                                <Setter.Value>
                                    <SolidColorBrush Color="#EBEBEB"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Foreground" Value="#333333"/>
            </Trigger>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                            <GradientStop Color="#F1F1F1" Offset="1"/>
                            <GradientStop Color="#F5F5F5" Offset="0"/>
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

ps上記のWPFで初心者の間違いを見つけた場合は、遠慮なく私に指摘してください。

4

3 に答える 3

8

私は過去に、と呼ばれる添付プロパティを定義することによってこれを行いましたExtendedProperties.CornerRadius。その後、自分のスタイルに設定できます。

<Style TargetType="Button">
    <Setter Property="local:ExtendedProperties.CornerRadius" Value="0"/>
    ...

そして、テンプレート内からそれを使用します:

<Border CornerRadius="{Binding Path=(local:ExtendedProperties.CornerRadius), RelativeSource={RelativeSource TemplatedParent}">

次に、他のプロパティをオーバーライドするのと同じ方法で、ローカルでオーバーライドします。

<Button Content="Archive" local:ExtendedProperties.CornerRadius="5,0,0,5"/>
<Button Content="Span"/>
<Button Content="Delete" local:ExtendedProperties.CornerRadius="0,5,5,0"/>

私の場合、これは私に与えます(明らかに、私のテーマは暗いです):

ここに画像の説明を入力してください

そして、テーマに添付されているいくつかのプロパティを微調整するだけで、次のエフェクトを作成しました。

ここに画像の説明を入力してください

このアプローチの利点は、サブクラス化する必要がないことButtonです。同じアタッチされたプロパティを使用して、他のコントロール(などTextBox)のコーナー半径を定義することもできます。もちろん、コーナー半径だけに限定されません。ベースコントロールには存在しない、テーマに固有のあらゆる種類のものにアタッチされたプロパティを定義できます。

不利な点は、それが付属のプロパティであるため、発見が難しいことです。テーマを文書化すると、この点で役立ちます。

だから、あなたの特定の質問に答えるために:

Q1。はい、上記の私の答えを参照してください。ローカルでオーバーライドするか、プロパティをオーバーライドする新しいスタイルを定義することができます。

Q2。灰色の領域です。私の意見では、それが純粋に視覚的(行動的ではない)である場合、スタイルが進むべき道です。もちろん、手に負えなくなった場合は、代わりにすべての組み込みコントロールをサブクラス化し、特定のプロパティを追加することをお勧めします。ただし、これにより、テーマの再利用が難しくなり、アプリケーションの開発がより面倒になります(標準のコントロールセットではなく、コントロールセットを使用する必要があるため)。

Q3。コードでは可能だと思いますが、コントロールコンシューマーとして使用するのは直感的ではありません。追加のアタッチされたプロパティを定義したほうがよいと思います。ExtendedProperties.HoverBackgroundExtendedProperties.PressedBackground-そしてテンプレートからのものをまったく同じ方法で使用します。次に、コントロールのコンシューマーは、コントロールがさまざまな状態にあるときに使用されるブラシをより細かく制御できます。私は過去にこれを行いましたが、他のコンテキストでそれらのプロパティを再利用できるように、より一般的なプロパティ名( SecondaryBackground、 )を使用しました。TernaryBackground繰り返しますが、テーマを文書化することは役に立ちます。

于 2011-08-16T07:48:26.547 に答える
2

Q1:私の知る限りではありません

Q2:スタイルが進むべき道だと思います。ボタンから派生し、左、中、右のいずれであるかに基づいて右隅の半径を選択する独自のクラスを作成できます。

Q3:カスタム値コンバーターと独自のスタイルで実行できるはずです。

結論として。この場合、周囲のスタックパネルに背景のグラデーションとコーナー半径を配置したいと思うかもしれません。ボタンはテキストに対して透明になります。そうすれば、個々のボタンの角の半径を処理する必要がなくなります。

編集:上記の第3四半期の回答のコードとスタイルを追加しました。OPへ; これがあなたが求めていたものであるかどうかはわかりませんが、おそらくここにあなたが興味を持つことができる何かがあります。

私があなたを解釈した方法は、ボタンの背景を特定の色に設定したいが、その色に基づいて線形グラデーションとしてレンダリングする必要があるというものでした。他のポスターは不透明マスクについて言及しており、それはまったく悪い考えではありません。カスタム値コンバーターを使用してそれを行う方法を示すと思いました。

アイデアは、単色ブラシを線形グラデーションブラシに変換する変換されたカスタム値を作成することです。次に、このコンバーターを使用して、ボタンの背景色を単色ブラシから線形グラデーションブラシに変換します。

カスタム値コンバーターは次のとおりです。

class SolidColorBrushToGradientConverter : IValueConverter
{
    const float DefaultLowColorScale = 0.95F;

    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        var solidColorBrush = value as SolidColorBrush;

        if (!targetType.IsAssignableFrom (typeof (LinearGradientBrush)) || solidColorBrush == null)
        {
            return Binding.DoNothing;
        }

        var lowColorScale = ParseParameterAsDouble (parameter);

        var highColor = solidColorBrush.Color;
        var lowColor = Color.Multiply (highColor, lowColorScale);
        lowColor.A = highColor.A;

        return new LinearGradientBrush (
            highColor,
            lowColor,
            new Point (0, 0),
            new Point (0, 1)
            );
    }

    static float ParseParameterAsDouble (object parameter)
    {
        if (parameter is float)
        {
            return (float)parameter;
        }
        else if (parameter is string)
        {
            float result;
            return float.TryParse(
                (string) parameter, 
                NumberStyles.Float, 
                CultureInfo.InvariantCulture, 
                out result
                        )
                        ? result
                        : DefaultLowColorScale
                ;
        }
        else
        {
            return DefaultLowColorScale;
        }
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

次に、これをあなたからコピーしたスタイルで参照します(基本的には同じですが、少し再構築しました)。重要な行の部分は次のとおりです。

Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"

これは、テンプレート化された親の背景(つまり、Button.Background)にバインドし、パラメーター0.95でコンバーターSolidColorBrushToGradientConverterを使用することを意味します(これにより、「低い」色を「高い」色と比較してどれだけ暗くするかが決まります)。

完全なスタイル:

<local:SolidColorBrushToGradientConverter x:Key="SolidColorBrushToGradientConverter" />

<Style x:Key="GoogleMiddleButton" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="#F5F5F5" />
    <Setter Property="Foreground" Value="#666666"/>
    <Setter Property="FontFamily" Value="Arial"/>
    <Setter Property="FontSize" Value="13"/>
    <Setter Property="FontWeight" Value="Bold"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border 
                    Name="dropShadowBorder"                        
                    BorderThickness="0,0,0,1"                        
                    CornerRadius="1"
                    >
                    <Border.BorderBrush>
                        <SolidColorBrush Color="#00000000"/>
                    </Border.BorderBrush>
                    <Border Name="border"                     
                            BorderThickness="{TemplateBinding BorderThickness}"                    
                            Padding="{TemplateBinding Padding}"                     
                            CornerRadius="0"                     
                            Background="{Binding Path=Background,Mode=OneWay,RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource SolidColorBrushToGradientConverter}, ConverterParameter=0.95}"
                            >
                        <Border.BorderBrush>
                            <SolidColorBrush Color="#D8D8D8"/>
                        </Border.BorderBrush>
                        <ContentPresenter 
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                   
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            />
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#939393"/>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                            <Setter.Value>
                                <SolidColorBrush Color="#EBEBEB"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter Property="Background" Value="#4A8FF7" />
                        <Setter Property="Foreground" Value="#F5F5F5" />
                        <Setter Property="BorderBrush" TargetName="border">
                            <Setter.Value>
                                <SolidColorBrush Color="#5185D8"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
于 2011-08-15T21:08:24.123 に答える
1

私はこの挑戦の外観が好きです!

Q1:他のコメント/回答は正しいです。テンプレートを変更または継承することはできません。ただし、外観を変更するためにテンプレートに値を渡す方法があります。簡単な(ただし少しハッキーな方法)のは、TagプロパティCornerRadiusを使用して境界線をテンプレートに渡すことです。enter code hereより良い方法は、ボタンをサブクラス化して「場所」プロパティを追加することです。

Q2:はい、あなたはスタイル/テンプレートで正しい方向に進んでいます

Q3:テンプレートを変更OpacityMaskして、希望のグラデーションを持つを含めます。次に、このマスクの後ろに要素を配置するか、マスクされた要素に背景色自体を使用させることができます。以下に示す完全な例:

ここに画像の説明を入力してください

<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">
  <Window.Resources>
    <Style x:Key="GoogleButton" TargetType="{x:Type Button}">      
      <Setter Property="Background" Value="White"/>
      <Setter Property="Foreground" Value="#666666"/>
      <Setter Property="Tag">
        <Setter.Value>
          <CornerRadius>0</CornerRadius>
        </Setter.Value>
      </Setter>
      <Setter Property="FontFamily" Value="Arial"/>
      <Setter Property="FontSize" Value="13"/>
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="Button">
            <Border Name="dropShadowBorder"
                    BorderThickness="0,0,0,1"
                    CornerRadius="1"
                    BorderBrush="Transparent"
                    Background="White">
              <Grid>
                <Border Name="backgroundFill" 
                        BorderBrush="Red"
                        Background="{TemplateBinding Background}"
                        CornerRadius="{TemplateBinding Tag}">
                  <Border.OpacityMask>
                    <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                      <GradientStop Color="#FF000000" Offset="0"/>
                      <GradientStop Color="#00000000" Offset="1"/>
                    </LinearGradientBrush>
                  </Border.OpacityMask>
                </Border>
                <Border Name="border" 
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Padding="{TemplateBinding Padding}" 
                    CornerRadius="{TemplateBinding Tag}" 
                    Background="Transparent">
                  <Border.BorderBrush>
                    <SolidColorBrush Color="#D8D8D8"/>
                  </Border.BorderBrush>
                  <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
              </Grid>
            </Border>            
            <ControlTemplate.Triggers>
              <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" TargetName="border">
                  <Setter.Value>
                    <SolidColorBrush Color="#939393"/>
                  </Setter.Value>
                </Setter>
                <Setter Property="BorderBrush" TargetName="dropShadowBorder">
                  <Setter.Value>
                    <SolidColorBrush Color="#EBEBEB"/>
                  </Setter.Value>
                </Setter>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Foreground" Value="#333333"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
          <Setter Property="Background">
            <Setter.Value>
              <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                <GradientStop Color="#F1F1F1" Offset="1"/>
                <GradientStop Color="#F5F5F5" Offset="0"/>
              </LinearGradientBrush>
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>
  <Grid>
    <StackPanel Orientation="Horizontal"
                VerticalAlignment="Top">
      <Button Style="{StaticResource GoogleButton}" Content="Archive">
        <Button.Tag>
          <CornerRadius>2,0,0,2</CornerRadius>
        </Button.Tag>
      </Button>
      <Button Style="{StaticResource GoogleButton}" Content="Spam"
              Background="LightBlue"/>
      <Button Style="{StaticResource GoogleButton}" Content="Delete">
        <Button.Tag>
          <CornerRadius>0,2,2,0</CornerRadius>
        </Button.Tag>
      </Button>
    </StackPanel>
  </Grid>
</Window>
于 2011-08-16T07:37:22.917 に答える