WPF Custom LED Checkbox

J’essaie actuellement de “porter” du contrôle de WindowsForms vers WPF. J’ai cette case à cocher stylée et j’essaie d’obtenir le même aspect visuel dans wpf. mais je suis incapable de le faire.

J’ai beaucoup cherché mais je ne trouve pas de solution à mes questions / problèmes.

Voici à quoi ressemble le contrôle winforms entrez la description de l'image ici

La taille du cercle coloré dépend de la taille du contrôle. La couleur est définissable par l’utilisateur. La couleur est utilisée pour le cercle et le texte. Il est shiny s’il est coché et estompé / gris s’il est décoché. Les couleurs diark et surlignées sont calculées à partir de la couleur de contrôle (plus claire / plus sombre).

Tous mes essais de faire la même chose dans wpf ont à peu près échoué jusqu’à présent. 🙁 J’ai essayé de le faire avec un contrôle utilisateur, mais j’ai décidé qu’il serait plus facile de le dériver à partir d’une case à cocher avec juste une option supplémentaire pour définir la couleur.

                 

Voici mon code LedControl:

                    

et le code derrière:

  public partial class LedControl : UserControl { #region Dependency properties /// Dependency property to Get/Set the current IsActive (True/False) public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool?), typeof(LedControl), new PropertyMetadata(null, new PropertyChangedCallback(LedControl.IsCheckedPropertyChanced))); /// Dependency property to Get/Set Color when IsActive is true 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(ssortingng), typeof(LedControl), new PropertyMetadata("ButtonText", new PropertyChangedCallback(LedControl.OnTextPropertyChanged))); #endregion #region Properties /// Gets/Sets Text Value public ssortingng Text { get { return (ssortingng)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } /// Gets/Sets Value public bool? IsChecked { get { return (bool?)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); } } /// Gets/Sets Color 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 = (Ssortingng)e.NewValue; } #endregion 

}

Le problème, c’est que le contrôle ne fonctionne pas. J’ai défini la couleur sur forrestGreen, mais s’affiche en rouge dans Designer et si j’exécute le programme:

entrez la description de l'image ici

Le texte “Une option” n’est pas affiché aussi ..

Je n’ai pas trouvé comment rendre les dégradés de couleurs plus sombres et plus clairs que la couleur souhaitée.

Le look de la led n’est pas aussi cool que dans winforms, mais je n’ai aucune idée pour traduire le code en wpf.

voici la partie du code qui dessine le led dans 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 != ssortingng.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); SsortingngFormat sf = new SsortingngFormat(); sf.Alignment = SsortingngAlignment.Near; sf.LineAlignment = SsortingngAlignment.Center; if (!this.On) g.DrawSsortingng(this.Text, fon, new SolidBrush(Color.Gray), textArea, sf); else g.DrawSsortingng(this.Text, fon, new SolidBrush(darkColor), textArea, sf); } } 

Mon deuxième essai avec la case à cocher en tant que base est nul ou moins inutile, mais peut-être que quelqu’un est intéressé et peut remplacer la case à cocher par le témoin.

Toute aide est appréciée!

Voici un LedControl dérivé de CheckBox. LedControl lui-même ajoute les propriétés OnColor et 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); } } } 

et l’apparence visuelle est personnalisée via Style et modèle. Les parties principales du modèle sont l’ellipse LedBorder ellipse blanche CenterGlow , la forme blanche CornerLight et, bien sûr, ContentPresent. LedBorder s’adapte à la hauteur de LedControl . Selon IsChecked LedBorder est coloré avec OnColor ou OffColor (ainsi que le premier plan). Le contrôle désactivé est grisé.

  

et voici un exemple:

       

entrez la description de l'image ici

Vous pouvez utiliser PathGradientBrush pour dessiner un dégradé radial. Voici le résultat du code que j’ai écrit. Vous pouvez utiliser n’importe quelle couleur comme CheckedColor et UnCheckedColor . J’ai utilisé le Red et le Green pour obtenir ce résultat:

entrez la description de l'image ici

Code

 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); } }