[英]WPF Custom LED Checkbox
我目前正在嘗試將某些控件從WindowsForms“移植”到WPF。 我有這個時尚的led復選框,並嘗試在wpf中實現相同的視覺外觀。 但我無法完成它。
我已經搜索了很多,但找不到我的問題/解決方案。
彩色的圓圈大小取決於控件的大小。 顏色是用戶定義的。 顏色用於圓和文本。 如果未選中,則檢查並變暗/灰色,這是明亮的。 暗色和高光顏色是根據控制色(較淺/較暗)計算得出的。
到目前為止,我在wpf中做相同的所有嘗試幾乎都失敗了。 :-(我的拳頭試圖用一個用戶控件來完成它,但是我決定將它從復選框中派生出來只是一個額外的選項來設置顏色會更容易。
<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>
這是我的LedControl代碼:
<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>
以及后面的代碼:
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
}
問題是該控件不起作用。 我將顏色設置為forrestGreen,但是在設計器中並且如果執行程序,則顯示為紅色:
文本“ Some Option”也未顯示。
我還沒有弄清楚如何使漸變顏色成為我想要的顏色的深色和淺色版本。
led的外觀也不像winforms那樣酷,但是我不知道將代碼轉換為wpf。
這是在win-Forms中繪制led的代碼部分:
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);
}
}
我第二次嘗試將復選框作為基礎是沒有意義的,或沒有什么用處,但是也許有人很熱衷,可以用led代替復選框。
任何幫助表示贊賞!
這是從CheckBox派生的LedControl。 LedControl本身添加了OnColor
和OffColor
屬性。
public class LedControl : CheckBox
{
static LedControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LedControl), new FrameworkPropertyMetadata(typeof(LedControl)));
}
public static readonly DependencyProperty OnColorProperty =
DependencyProperty.Register("OnColor", typeof(Brush), typeof(LedControl), new PropertyMetadata(Brushes.Green));
public Brush OnColor
{
get { return (Brush)GetValue(OnColorProperty); }
set { SetValue(OnColorProperty, value); }
}
public static readonly DependencyProperty OffColorProperty =
DependencyProperty.Register("OffColor", typeof(Brush), typeof(LedControl), new PropertyMetadata(Brushes.Red));
public Brush OffColor
{
get { return (Brush)GetValue(OffColorProperty); }
set { SetValue(OffColorProperty, value); }
}
}
外觀通過樣式和模板自定義。 主要模板部分是LedBorder
橢圓,白色CenterGlow
橢圓,白色CornerLight
形狀,當然還有ContentPresent。 LedBorder
適應LedControl
高度。 根據IsChecked
LedBorder
會用OnColor
或OffColor
(以及前景) OffColor
。 禁用的控件為灰色。
<Style TargetType="local:LedControl">
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:LedControl">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Background="Transparent" Name="grd"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Stretch"
Width="{Binding Path=ActualHeight, Mode=OneWay, RelativeSource={RelativeSource Self}}">
<Ellipse x:Name="LedBorder"
Fill="{TemplateBinding Background}"
Stroke="{TemplateBinding BorderBrush}"
StrokeThickness="2"
Stretch="Uniform"/>
<Ellipse x:Name="CenterGlow" Stretch="Uniform">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="White" Offset="-0.25"/>
<GradientStop Color="Transparent" Offset="0.91"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="CornerLight" Stretch="Uniform" Margin="2">
<Ellipse.Fill>
<RadialGradientBrush Center="0.15 0.15" RadiusX="0.5" RadiusY="0.5">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Transparent" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
<ContentPresenter x:Name="content" Grid.Column="1" Margin="4,0,0,0"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter TargetName="LedBorder" Property="Fill" Value="{Binding Path=OnColor, RelativeSource={RelativeSource TemplatedParent}}"/>
<Setter TargetName="content" Property="TextElement.Foreground" Value="{Binding Path=OnColor, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="IsChecked" Value="false">
<Setter TargetName="LedBorder" Property="Fill" Value="{Binding Path=OffColor, RelativeSource={RelativeSource TemplatedParent}}"/>
<Setter TargetName="content" Property="TextElement.Foreground" Value="{Binding Path=OffColor, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="CenterGlow" Property="Fill">
<Setter.Value>
<RadialGradientBrush Opacity="1">
<GradientStop Color="Transparent" Offset="-0.5" />
<GradientStop Color="#888" Offset="1" />
</RadialGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="content" Property="TextElement.Foreground" Value="#888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
這是一個示例:
<StackPanel>
<local:LedControl Content="Disabled OFF" Height="24" IsChecked="False" IsEnabled="False" />
<local:LedControl Content="Disabled ON" Height="32" IsChecked="True" IsEnabled="False" />
<local:LedControl Content="Enabled OFF" OffColor="Chocolate" IsChecked="False" Height="40" />
<local:LedControl Content="Enabled ON" OnColor="Navy" IsChecked="True" Height="48" />
</StackPanel>
您可以使用PathGradientBrush
繪制徑向漸變。 這是我編寫的代碼的結果。 您可以將任何顏色用作CheckedColor
和UnCheckedColor
,我使用Red
和Green
可以得到以下結果:
碼
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class MyCheckBox : CheckBox
{
public MyCheckBox()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.DoubleBuffered = true;
this.ResizeRedraw = true;
CheckedColor = Color.Green; ;
UnCheckedColor = Color.Red; ;
}
[DefaultValue(typeof(Color), "Green")]
public Color CheckedColor { get; set; }
[DefaultValue(typeof(Color), "Red")]
public Color UnCheckedColor { get; set; }
protected override void OnPaint(PaintEventArgs e)
{
var darkColor = Color.Black;
var lightColor = Color.FromArgb(200, Color.White);
var cornerAlpha = 80;
this.OnPaintBackground(e);
using (var path = new GraphicsPath())
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var rect = new Rectangle(0, 0, Height, Height);
path.AddEllipse(rect);
rect.Inflate(-1, -1);
using (var bgBrush = new SolidBrush(darkColor))
{
e.Graphics.FillEllipse(bgBrush, rect);
}
using (var pathGrBrush = new PathGradientBrush(path))
{
var color = Checked ? CheckedColor : UnCheckedColor;
pathGrBrush.CenterColor = color; ;
Color[] colors = { Color.FromArgb(cornerAlpha, color) };
pathGrBrush.SurroundColors = colors;
e.Graphics.FillEllipse(pathGrBrush, rect);
}
using (var pathGrBrush = new PathGradientBrush(path))
{
pathGrBrush.CenterColor = lightColor; ;
Color[] colors = { Color.Transparent };
pathGrBrush.SurroundColors = colors;
var r = (float)(Math.Sqrt(2) * Height / 2);
var x = r / 8;
e.Graphics.FillEllipse(pathGrBrush, new RectangleF(-x, -x, r, r));
e.Graphics.ResetClip();
}
}
TextRenderer.DrawText(e.Graphics, Text, Font,
new Rectangle(Height, 0, Width - Height, Height), ForeColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.