2017-03-17 6 views
2

Ich versuche derzeit, einige Kontrolle von WindowsForms zu WPF "portieren". Ich habe dieses stilvolle LED-Kontrollkästchen und versuchen, das gleiche visuelle Erscheinungsbild in WPF zu erreichen. aber ich kann es nicht schaffen.WPF benutzerdefinierte LED Checkbox

Ich habe viel Hintern gesucht kann keine Lösung für meine Fragen/Probleme finden. Dies ist

wie die WinForms Kontrolle sieht aus wie enter image description here

Der farbige Kreis Größe auf die Größe der Steuerung abhängt. Die Farbe ist benutzerdefinierbar. Die Farbe wird für den Kreis und den Text verwendet. Es ist hell, wenn es aktiviert und abgeblendet/grau ist, wenn es nicht aktiviert ist. Die Farben Diark und Highlight werden aus der Kontrollfarbe (heller/dunkler) berechnet.

Alle meine Versuche, das gleiche in Wpf zu tun, ist bisher ziemlich gescheitert. :-( I Faust versuchte es mit einem Usercontrol zu tun, aber beschlossen, es wäre einfacher, es aus Checkbox mit nur einer zusätzlichen Option, um die Farbe einzustellen abgeleitet zu haben

<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> 

Das ist mein LEDControl Code ist.

<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> 

und der Code hinter:

 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 

}

Die Kontrolle funktioniert nicht. Ich habe die Farbe zu forrestGreen, zeige aber in Designern rot, und wenn ich das Programm ausführen:

enter image description here

Der Text „Eine Option“ ist nicht so gut gezeigt ..

Ich habe nicht habe herausgefunden, wie die Farbverläufe dunkler und heller sein können. Das Aussehen der LED ist auch nicht so cool wie in Winforms, aber ich habe keine Ahnung, den Code zu wpf zu übersetzen.

hier ist der Teil des Codes, der führt in Win-Forms zieht:

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

    } 

Mein zweiter Versuch mit der Checkbox als Basis nore oder weniger nutzlos, aber vielleicht jemand daran interessiert, und das ersetzen kann Kontrollkästchen mit der LED.

Jede Hilfe wird geschätzt!

Antwort

2

hier ein LEDControl von CheckBox abgeleitet ist. LedControl selbst fügt OnColor und OffColor Eigenschaften hinzu.

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

und das visuelle Erscheinungsbild wird über Style und Template angepasst. Hauptschablonenteile sind LedBorder Ellipse, weiß CenterGlow Ellipse, weiß CornerLight Form und natürlich ContentPresent. LedBorder passt sich an LedControl Höhe an. Je nach IsChecked wird LedBorder mit OnColor oder OffColor (sowie Foreground) eingefärbt. Deaktivierte Steuerung ist abgeblendet.

<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> 

und hier ist ein Beispiel:

<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> 

enter image description here

+0

Thankz für die Weitergabe Ihres Wissens. Ich habe einige Änderungen an meinen Bedürfnissen vorgenommen, aber praktisch war das, was ich brauchte. –

2

Sie können PathGradientBrush verwenden, um einen radialen Farbverlauf zu zeichnen. Hier ist das Ergebnis des Codes, den ich geschrieben habe.Sie können jede Farbe als CheckedColor verwenden und UnCheckedColor, benutzte ich Red und Green dieses Ergebnis zu erhalten:

enter image description here

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

dies auf den ersten Blick ziemlich cool aussieht. Ich werde es nach den Ferien sehen. Also gib mir etwas Zeit dafür. –

+2

Ich dachte, du willst eine LED-CheckBox in Windows Forms erstellen, also habe ich die Antwort gepostet, aber es scheint, dass du das umgekehrt brauchst. Aber ich bevorzuge, den Code zu behalten, weil ich denke, dass es eine elegante Windows Forms LED CheckBox ist. –

+0

Stört es nicht. Ich dachte zuerst, das ist der richtige Weg. Aber wie du schon erwähnt hast, sind es Windows-Formulare. Aber ich brauche es für wpf. –

Verwandte Themen