lighten background color on button click per bindi

2019-02-19 00:43发布

问题:

I want to lighten a buttons background on click. So I did the following:

<converter:ColorLightConverter x:Key="colorLightConverter" />

...

<Style BasedOn="{StaticResource default}" TargetType="{x:Type controls:Button}">            
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:Button}">
                    <ControlTemplate.Triggers>                            
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background">
                                <Setter.Value>
                                    <SolidColorBrush Color="{Binding Path=Background.Color, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource colorLightConverter}}" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="Transparent"
                            BorderThickness="0">
                        ...                            
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

The converter:

class ColorLightConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Color color = (Color)value;
            System.Drawing.Color lightColor = ControlPaint.Light(System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B));

            return Color.FromArgb(lightColor.A, lightColor.R, lightColor.G, lightColor.B);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

But the converter isn't called when I click the button. I think there is anything wrong with the binding, but I can't see the error...

Can you help me?

Maybe I'm completely wrong. What I basically want to do: When clicking the button, take the current background color and lighten it. Not more...

Update 1:

I tried the following:

Changed the binding a bit:

<Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" Value="{Binding Path=Background.Color, RelativeSource={RelativeSource Self}, Converter={StaticResource colorLightConverter}}" />
                        </Trigger>

Changed the converter (now it returns a SolidColorBrush):

class ColorLightConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Color color = (Color)value;
            System.Drawing.Color lightColor = ControlPaint.Light(System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B));

            return new SolidColorBrush(Color.FromArgb(lightColor.A, lightColor.R, lightColor.G, lightColor.B));
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Now the converter is called, but it is called again and again, so a stackoverflow exception is thrown after a few seconds. Where comes this indefinite loop from? I'm really a bit confused at the moment...

回答1:

You shouldn't be using System.Drawing.Color on WPF. Use System.Windows.Media.Color instead. Another important thing is that the Setters inside the ControlTemplate.Triggers do not have to reference the control by using RelativeSource TemplatedParent. Just:

<Trigger Property="IsPressed" Value="True">
    <Setter Property="Background" Value="YourLightColor"/>
</Trigger>

And keep the rest the same. Now, if you need to specify custom logic (such as a converter, just place the converter in that setter.

Edit: The infinite loop comes from the fact that you're Binding to Background.Color, and then Setting Background, which triggers a Property Change notification into the WPF Property System, which in turn causes the Binding to be refreshed, and so on... I think you might be able to work around this by setting the binding Mode to = OneTime



回答2:

i have used following style for Button. it may help you .

  <Style TargetType="{x:Type Button}">
    <!-- General for all buttons -->
    <Setter Property="Foreground"
            Value="Azure" />
    <Setter Property="FontFamily"
            Value="Verdana" />
    <Setter Property="FontSize"
            Value="12" />
    <Setter Property="FontWeight"
            Value="Bold" />
    <Setter Property="Margin"
            Value="4,4,4,4"></Setter>
    <Setter Property="VerticalAlignment"
            Value="Center"></Setter>
    <Setter Property="Background">
        <Setter.Value>
            <RadialGradientBrush>
                <GradientStop Color="#145082"
                              Offset="0" />
                <GradientStop Color="Black"
                              Offset="1" />
            </RadialGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Grid>
                    <Rectangle x:Name="GelBackground"
                               Opacity="1"
                               RadiusX="9"
                               RadiusY="9"
                               Fill="{TemplateBinding Background}"></Rectangle>
                    <Rectangle x:Name="GelShine"
                               Margin="2,2,2,0"
                               VerticalAlignment="Top"
                               RadiusX="4"
                               RadiusY="4"
                               Opacity=".8"
                               Stroke="Transparent"
                               Height="15">
                        <Rectangle.Fill>
                            <LinearGradientBrush StartPoint="0,0"
                                                 EndPoint="0,1">
                                <GradientStop Color="#ccffffff"
                                              Offset="0" />
                                <GradientStop Color="Transparent"
                                              Offset="1" />
                            </LinearGradientBrush>
                        </Rectangle.Fill>
                    </Rectangle>
                    <ContentPresenter Margin="10,0,10,0"
                                      VerticalAlignment="Center"
                                      HorizontalAlignment="Center" />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver"
                             Value="true">
                        <Setter Property="Foreground"
                                Value="White" />
                        <Setter Property="FontSize"
                                Value="12" />
                        <Setter Property="Rectangle.Fill"
                                TargetName="GelBackground">
                            <Setter.Value>
                                <RadialGradientBrush>
                                    <GradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="Tomato"
                                                          Offset="0" />
                                            <GradientStop Color="Black"
                                                          Offset="1" />
                                        </GradientStopCollection>
                                    </GradientBrush.GradientStops>
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed"
                             Value="true">
                        <Setter Property="Foreground"
                                Value="Black" />
                        <Setter Property="Fill"
                                TargetName="GelBackground">
                            <Setter.Value>
                                <RadialGradientBrush>
                                    <GradientStop Color="#ffcc00"
                                                  Offset="0" />
                                    <GradientStop Color="#cc9900"
                                                  Offset="1" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled"
                             Value="false">
                        <Setter Property="Foreground"
                                Value="Black" />
                        <Setter Property="Fill"
                                TargetName="GelBackground">
                            <Setter.Value>
                                <RadialGradientBrush>
                                    <GradientStop Color="White"
                                                  Offset="0" />
                                    <GradientStop Color="#333333"
                                                  Offset=".4" />
                                    <GradientStop Color="#111111"
                                                  Offset=".6" />
                                    <GradientStop Color="#000000"
                                                  Offset=".7" />
                                    <GradientStop Color="#000000"
                                                  Offset="1" />
                                </RadialGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


回答3:

The problem is with Background, I don't know exactly why of all properties, background always acts this way but if you set Template instead of Background, the problem is solved:

    <Style TargetType="{x:Type controls:Button}">
        <Style.Triggers>
            <Trigger Property="IsPressed" Value="True">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type controls:Button}">
                            <Border>
                                <Border.Background>
                                    <SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                                        Path=Background.Color, Converter={StaticResource colorLightConverter}}"/>
                                </Border.Background>
                                <ContentPresenter Content="{TemplateBinding Content}"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Setter Property="Template">
        <Setter.Value.../>
    </Setter>
    </Style>