I currently trying to "port" some control from WindowsForms to WPF.
I Have this stylish led checkbox and try to achieve the same visual appearance in wpf. but I'm unable to get it done.
I've searched a lot butt cannot find a solution to my questions/problems.
This is how the winforms Control looks like
The colored Circle size depends on the size of the control.
The color is user definable. The color is used for the circle and the Text.
It's bright if it ich checked and dimmed / gray when it's unchecked.
The diark and highlight colors are calculated from the control color (lighter/darker).
All my tries to do the same in wpf pretty much failed up to now. :-(
I fist tried to do it with an usercontrol, but decided it would be easier to have it derived from checkbox with just an extra option to set the color.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:test="clr-namespace:LedTest"
xmlns:uc="clr-namespace:WPFTest;assembly=LedControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="LedTest.MainWindow"
Title="MainWindow" Height="285" Width="566">
<Window.Resources>
<ResourceDictionary x:Key="ResDict2" Source="Dictionary2.xaml"/>
</Window.Resources>
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="27" />
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="179*"/>
</Grid.ColumnDefinitions>
<uc:LedControl x:Name="led1"
Color="ForestGreen" Text="Some Option"
Grid.Column="1" Grid.Row="1" Height="39" VerticalAlignment="Bottom" Margin="0,0,0,36"/>
<CheckBox Content="Some Option" Style="{DynamicResource TestStyle}" Margin="0,0,31,0" Grid.Column="1"/>
</Grid>
</Window>
This is my LedControl code:
<UserControl x:Class="LedControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="300">
<UserControl.Resources>
</UserControl.Resources>
<StackPanel x:Name="gridBigLed" Orientation="Horizontal" >
<Border x:Name="border1"
BorderThickness="1"
Width="{Binding ActualHeight, ElementName=gridBigLed, Mode=OneWay}"
CornerRadius="{Binding ActualWidth, ElementName=gridBigLed, Mode=OneWay}"
HorizontalAlignment="Left">
<Border.Background>
<RadialGradientBrush GradientOrigin="0.2,0.2">
<GradientStop Color="#FFFFAAAA"/>
<GradientStop x:Name="backgroundColor" Color="Red" Offset="1.2"/>
</RadialGradientBrush>
</Border.Background>
<Border.BorderBrush>
<RadialGradientBrush>
<GradientStop x:Name="GradientColorLow" Color="#FF660000" Offset="0.383"/>
<GradientStop x:Name="GradientColorHigh" Color="#330000" Offset="0.5"/>
</RadialGradientBrush>
</Border.BorderBrush>
</Border>
<Label Content="{Binding Text}" x:Name="LEDText" Foreground="Red" HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
</StackPanel>
</UserControl>
and the code behind:
public partial class LedControl : UserControl
{
#region Dependency properties
/// <summary>Dependency property to Get/Set the current IsActive (True/False)</summary>
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool?), typeof(LedControl),
new PropertyMetadata(null, new PropertyChangedCallback(LedControl.IsCheckedPropertyChanced)));
/// <summary>Dependency property to Get/Set Color when IsActive is true</summary>
public static readonly DependencyProperty ColorProperty =
DependencyProperty.Register("Color", typeof(Color), typeof(LedControl),
new PropertyMetadata(Colors.Green, new PropertyChangedCallback(LedControl.OnColorPropertyChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(LedControl),
new PropertyMetadata("ButtonText", new PropertyChangedCallback(LedControl.OnTextPropertyChanged)));
#endregion
#region Properties
/// <summary>Gets/Sets Text Value</summary>
public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } }
/// <summary>Gets/Sets Value</summary>
public bool? IsChecked { get { return (bool?)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); } }
/// <summary>Gets/Sets Color</summary>
public Color Color { get { return (Color)GetValue(ColorProperty); } set { SetValue(ColorProperty, value); } }
#endregion
#region Constructor
public LedControl()
{
InitializeComponent();
if (this.IsChecked == true)
{
this.LEDColor.Color = this.Color;
this.LEDText.Foreground = new SolidColorBrush(this.Color);
}
else if (this.IsChecked == false)
{
this.LEDColor.Color = Colors.Gray;
this.LEDText.Foreground = new SolidColorBrush(Colors.Gray);
}
}
#endregion
#region Callbacks
private static void IsCheckedPropertyChanced(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LedControl led = (LedControl)d;
if (led.IsChecked == true)
{
led.LEDColor.Color = led.Color;
led.LEDText.Foreground = new SolidColorBrush(led.Color);
}
else
{
led.LEDColor.Color = Colors.Gray; // TODO calculate dark/gray color
led.LEDText.Foreground = new SolidColorBrush(Colors.Gray);
}
}
private static void OnColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LedControl led = (LedControl)d;
led.Color = (Color)e.NewValue;
if (led.IsChecked == true)
{
led.LEDColor.Color = led.Color;
led.LEDText.Foreground = new SolidColorBrush( led.Color );
}
}
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LedControl led = (LedControl)d;
led.Text = (String)e.NewValue;
}
#endregion
}
The thing is that the control does not work. I set the Color to forrestGreen, but shows up red in designer and if I execute the program:
The text "Some Option" is not shown as well..
I haven't figured out how to have the gradient colors to be darker and lighter versions of the color I want.
The look of the led is also not as cool as in winforms,
but I have no clue to translate the code to wpf.
here is the part of the code that draws the led in win-Forms:
private void drawControl(Graphics g, bool on) {
// Is the bulb on or off
Color lightColor = (on) ? this.Color : Color.FromArgb(100, this.Color);
Color darkColor = (on) ? this.DarkColor : Color.Gray/*this.DarkDarkColor*/;
// Calculate the dimensions of the bulb
int width = this.Width - (this.Padding.Left + this.Padding.Right);
int height = this.Height - (this.Padding.Top + this.Padding.Bottom);
// Diameter is the lesser of width and height
int diameter = Math.Min(width, height);
// Subtract 1 pixel so ellipse doesn't get cut off
diameter = Math.Max(diameter - 1, 1);
SolidBrush br = new SolidBrush(BackColor);
g.FillRectangle(br, ClientRectangle);
// Draw the background ellipse
var rectangle = new Rectangle(this.Padding.Left, this.Padding.Top, diameter, diameter);
g.FillEllipse(new SolidBrush(darkColor), rectangle);
// Draw the glow gradient
var path = new GraphicsPath();
path.AddEllipse(rectangle);
var pathBrush = new PathGradientBrush(path);
pathBrush.CenterColor = lightColor;
pathBrush.SurroundColors = new Color[] { Color.FromArgb(0, lightColor) };
g.FillEllipse(pathBrush, rectangle);
// Draw the white reflection gradient
var offset = Convert.ToInt32(diameter * .15F);
var diameter1 = Convert.ToInt32(rectangle.Width * .8F);
var whiteRect = new Rectangle(rectangle.X - offset, rectangle.Y - offset, diameter1, diameter1);
var path1 = new GraphicsPath();
path1.AddEllipse(whiteRect);
var pathBrush1 = new PathGradientBrush(path);
pathBrush1.CenterColor = _reflectionColor;
pathBrush1.SurroundColors = _surroundColor;
g.FillEllipse(pathBrush1, whiteRect);
// Draw the border
g.SetClip(this.ClientRectangle);
if (this.On)
g.DrawEllipse(new Pen(Color.FromArgb(85, Color.Black),1F), rectangle);
if (this.Text != string.Empty)
{
RectangleF textArea = this.ClientRectangle;
textArea.X += rectangle.Width + 6;
textArea.Width -= (diameter + 6);
Font fon = new Font(Font.FontFamily, Font.Size-1, FontStyle.Bold);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Center;
if (!this.On)
g.DrawString(this.Text, fon, new SolidBrush(Color.Gray), textArea, sf);
else
g.DrawString(this.Text, fon, new SolidBrush(darkColor), textArea, sf);
}
}
My second try with the checkbox as base is nore or less useless, but perhaps someone is keen and can substitute the checkbox with the led.
Any help is appreciated!
See Question&Answers more detail:
os