将其样式移动到Window.Resources时,控件会消失

时间:2017-07-06 10:32:57

标签: wpf user-controls gauge

所以我有Gauge控件:

Gauge.xaml

<Style TargetType="controlsGauge:Gauge">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controlsGauge:Gauge">
                <Viewbox>
                    <Grid Height="200"
                          Width="200">
                        <!-- Ticks -->
                        <Line x:Name="TicksProxy"
                              Visibility="Collapsed"
                              Fill="{TemplateBinding TickBrush}" />
                        <ItemsControl ItemsSource="{TemplateBinding Ticks}"
                                      VerticalAlignment="Center"
                                      HorizontalAlignment="Center">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle Height="15"
                                               Width="4"
                                               Fill="{Binding Fill, ElementName=TicksProxy}">
                                        <Rectangle.RenderTransform>
                                            <TransformGroup>
                                                <TranslateTransform X="-2.5"
                                                                    Y="-95" />
                                                <RotateTransform Angle="{Binding}" />
                                            </TransformGroup>
                                        </Rectangle.RenderTransform>
                                    </Rectangle>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>

                        <!-- Scale -->
                        <Path Name="PART_Scale"
                              Stroke="{TemplateBinding ScaleBrush}"
                              StrokeThickness="{TemplateBinding ScaleWidth}" />

                        <!-- Trail -->
                        <Path Name="PART_Trail"
                              Stroke="{TemplateBinding TrailBrush}"
                              StrokeThickness="{TemplateBinding ScaleWidth}" />
                        <!-- Scale Ticks -->
                        <Line x:Name="ScaleTicksProxy"
                              Visibility="Collapsed"
                              Fill="{TemplateBinding ScaleTickBrush}"
                              X1="{TemplateBinding ScaleWidth}" />
                        <ItemsControl ItemsSource="{TemplateBinding Ticks}"
                                      VerticalAlignment="Center"
                                      HorizontalAlignment="Center">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle Height="{Binding X1, ElementName=ScaleTicksProxy}"
                                               Width="2"
                                               Fill="{Binding Fill, ElementName=ScaleTicksProxy}">
                                        <Rectangle.RenderTransform>
                                            <TransformGroup>
                                                <TranslateTransform X="-0.5"
                                                                    Y="-77" />
                                                <RotateTransform Angle="{Binding}" />
                                            </TransformGroup>
                                        </Rectangle.RenderTransform>
                                    </Rectangle>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>

                        <!-- Value and Unit -->
                        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,145,0,0">
                            <StackPanel.RenderTransform>
                                <RotateTransform Angle="0.5"/>
                            </StackPanel.RenderTransform>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Name="PART_ValueText"
                                       Foreground="Orange"
                                       FontSize="16"
                                       FontFamily="Comic Sans MS"
                                       FontWeight="SemiBold"
                                       Text="{TemplateBinding Value}"
                                       TextAlignment="Center"
                                       Margin="0 0 0 0" />
                                <TextBlock Foreground="Orange"
                                       FontSize="16"
                                       FontFamily="Comic Sans MS"
                                       FontWeight="SemiBold"
                                       Text="%"
                                       Margin="0 0 0 0" />
                            </StackPanel>
                            <TextBlock Foreground="{TemplateBinding UnitBrush}"
                                       FontSize="16"
                                       TextAlignment="Center"
                                       Text="{TemplateBinding Unit}"
                                       Margin="0" />
                        </StackPanel>

                        <!-- Needle -->
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>

                            <!-- The RenderTransform is in code behind. -->
                            <Path Name="PART_Needle"
                                  Stretch="Uniform"
                                  HorizontalAlignment="Center"
                                  Fill="{TemplateBinding NeedleBrush}"
                                  Data="M 0,0 l 0,100 l 5,0 l 0,-100 l -5,0"
                                  RenderTransformOrigin="0.5,1">
                            </Path>
                        </Grid>
                    </Grid>
                </Viewbox>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Gauge.cs


[TemplatePart(Name = NeedlePartName, Type = typeof(Path))]
[TemplatePart(Name = ScalePartName, Type = typeof(Path))]
[TemplatePart(Name = TrailPartName, Type = typeof(Path))]
[TemplatePart(Name = ValueTextPartName, Type = typeof(TextBlock))]
public class Gauge : UserControl
{
    #region Constants

    private const string NeedlePartName = "PART_Needle";

    private const string ScalePartName = "PART_Scale";

    private const string TrailPartName = "PART_Trail";

    private const string ValueTextPartName = "PART_ValueText";

    private const double Degrees2Radians = Math.PI / 180;

    #endregion Constants

    #region Dependency Property Registrations

    public static readonly DependencyProperty MinimumProperty =
        DependencyProperty.Register("Minimum", typeof(double), typeof(Gauge), new PropertyMetadata(0.0));

    public static readonly DependencyProperty MaximumProperty =
        DependencyProperty.Register("Maximum", typeof(double), typeof(Gauge), new PropertyMetadata(100.0));

    public static readonly DependencyProperty ScaleWidthProperty =
        DependencyProperty.Register("ScaleWidth", typeof(Double), typeof(Gauge), new PropertyMetadata(26.0));

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(double), typeof(Gauge), new PropertyMetadata(0.0, OnValueChanged));

    public static readonly DependencyProperty UnitProperty =
        DependencyProperty.Register("Unit", typeof(string), typeof(Gauge), new PropertyMetadata(string.Empty));

    public static readonly DependencyProperty NeedleBrushProperty =
        DependencyProperty.Register("NeedleBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.OrangeRed)));

    public static readonly DependencyProperty ScaleBrushProperty =
        DependencyProperty.Register("ScaleBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.LightGray)));

    public static readonly DependencyProperty TickBrushProperty =
        DependencyProperty.Register("TickBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));

    public static readonly DependencyProperty TrailBrushProperty =
        DependencyProperty.Register("TrailBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.Orange)));

    public static readonly DependencyProperty ValueBrushProperty =
        DependencyProperty.Register("ValueBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));

    public static readonly DependencyProperty ScaleTickBrushProperty =
        DependencyProperty.Register("ScaleTickBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.White)));

    public static readonly DependencyProperty UnitBrushProperty =
        DependencyProperty.Register("UnitBrush", typeof(Brush), typeof(Gauge), new PropertyMetadata(new SolidColorBrush(Colors.DimGray)));

    public static readonly DependencyProperty ValueStringFormatProperty =
        DependencyProperty.Register("ValueStringFormat", typeof(string), typeof(Gauge), new PropertyMetadata("N0"));

    protected static readonly DependencyProperty ValueAngleProperty =
        DependencyProperty.Register("ValueAngle", typeof(double), typeof(Gauge), new PropertyMetadata(null));

    public static readonly DependencyProperty TicksProperty =
        DependencyProperty.Register("Ticks", typeof(IEnumerable<double>), typeof(Gauge), new PropertyMetadata(null));

    #endregion Dependency Property Registrations

    #region Constructors

    public Gauge()
    {
        this.DefaultStyleKey = typeof(Gauge);
        this.Ticks = this.getTicks();
    }

    #endregion Constructors

    #region Properties

    public double Minimum
    {
        get { return (double)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }

    public double Maximum
    {
        get { return (double)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }

    public Double ScaleWidth
    {
        get { return (Double)GetValue(ScaleWidthProperty); }
        set { SetValue(ScaleWidthProperty, value); }
    }

    public double Value
    {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public string Unit
    {
        get { return (string)GetValue(UnitProperty); }
        set { SetValue(UnitProperty, value); }
    }

    public Brush NeedleBrush
    {
        get { return (Brush)GetValue(NeedleBrushProperty); }
        set { SetValue(NeedleBrushProperty, value); }
    }

    public Brush TrailBrush
    {
        get { return (Brush)GetValue(TrailBrushProperty); }
        set { SetValue(TrailBrushProperty, value); }
    }

    public Brush ScaleBrush
    {
        get { return (Brush)GetValue(ScaleBrushProperty); }
        set { SetValue(ScaleBrushProperty, value); }
    }

    public Brush ScaleTickBrush
    {
        get { return (Brush)GetValue(ScaleTickBrushProperty); }
        set { SetValue(ScaleTickBrushProperty, value); }
    }

    public Brush TickBrush
    {
        get { return (Brush)GetValue(TickBrushProperty); }
        set { SetValue(TickBrushProperty, value); }
    }

    public Brush ValueBrush
    {
        get { return (Brush)GetValue(ValueBrushProperty); }
        set { SetValue(ValueBrushProperty, value); }
    }

    public Brush UnitBrush
    {
        get { return (Brush)GetValue(UnitBrushProperty); }
        set { SetValue(UnitBrushProperty, value); }
    }

    public string ValueStringFormat
    {
        get { return (string)GetValue(ValueStringFormatProperty); }
        set { SetValue(ValueStringFormatProperty, value); }
    }

    public double ValueAngle
    {
        get { return (double)GetValue(ValueAngleProperty); }
        set { SetValue(ValueAngleProperty, value); }
    }

    public IEnumerable<double> Ticks
    {
        get { return (IEnumerable<double>)GetValue(TicksProperty); }
        set { SetValue(TicksProperty, value); }
    }

    #endregion Properties

    public override void OnApplyTemplate()
    {
        // Draw Scale
        var scale = this.GetTemplateChild(ScalePartName) as Path;
        if (scale != null)
        {
            var pg = new PathGeometry();
            var pf = new PathFigure();
            pf.IsClosed = false;
            var middleOfScale = 77 - this.ScaleWidth / 2;
            pf.StartPoint = this.ScalePoint(-150, middleOfScale);
            var seg = new ArcSegment();
            seg.SweepDirection = SweepDirection.Clockwise;
            seg.IsLargeArc = true;
            seg.Size = new Size(middleOfScale, middleOfScale);
            seg.Point = this.ScalePoint(150, middleOfScale);
            pf.Segments.Add(seg);
            pg.Figures.Add(pf);
            scale.Data = pg;
        }

        OnValueChanged(this, new DependencyPropertyChangedEventArgs());
        base.OnApplyTemplate();
    }

    private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Gauge c = (Gauge)d;
        if (!Double.IsNaN(c.Value))
        {
            var middleOfScale = 77 - c.ScaleWidth / 2;
            var needle = c.GetTemplateChild(NeedlePartName) as Path;
            var valueText = c.GetTemplateChild(ValueTextPartName) as TextBlock;
            c.ValueAngle = c.ValueToAngle(c.Value);

            // Needle
            if (needle != null)
            {
                needle.RenderTransform = new RotateTransform() { Angle = c.ValueAngle };
            }

            // Trail
            var trail = c.GetTemplateChild(TrailPartName) as Path;
            if (trail != null)
            {
                if (c.ValueAngle > -146)
                {
                    trail.Visibility = Visibility.Visible;
                    var pg = new PathGeometry();
                    var pf = new PathFigure();
                    pf.IsClosed = false;
                    pf.StartPoint = c.ScalePoint(-150, middleOfScale);
                    var seg = new ArcSegment();
                    seg.SweepDirection = SweepDirection.Clockwise;
                    // We start from -150, so +30 becomes a large arc.
                    seg.IsLargeArc = c.ValueAngle > 30;
                    seg.Size = new Size(middleOfScale, middleOfScale);
                    seg.Point = c.ScalePoint(c.ValueAngle, middleOfScale);
                    pf.Segments.Add(seg);
                    pg.Figures.Add(pf);
                    trail.Data = pg;
                }
                else
                {
                    trail.Visibility = Visibility.Collapsed;
                }
            }

            // Value Text
            if (valueText != null)
            {
                valueText.Text = c.Value.ToString(c.ValueStringFormat);
            }
        }
    }

    private Point ScalePoint(double angle, double middleOfScale)
    {
        return new Point(100 + Math.Sin(Degrees2Radians * angle) * middleOfScale, 100 - Math.Cos(Degrees2Radians * angle) * middleOfScale);
    }

    private double ValueToAngle(double value)
    {
        double minAngle = -150;
        double maxAngle = 150;

        // Off-scale to the left
        if (value < this.Minimum)
        {
            return minAngle - 7.5;
        }

        // Off-scale to the right
        if (value > this.Maximum)
        {
            return maxAngle + 7.5;
        }

        double angularRange = maxAngle - minAngle;

        return (value - this.Minimum) / (this.Maximum - this.Minimum) * angularRange + minAngle;
    }

    private IEnumerable<double> getTicks()
    {
        double tickSpacing = (this.Maximum - this.Minimum) / 10;
        for (double tick = this.Minimum; tick <= this.Maximum; tick += tickSpacing)
        {
            yield return ValueToAngle(tick);
        }
    }
}

主要XAML

xmlns:Controllers="clr-namespace:MyApplication.Controllers"

我的controls

<Controllers:Gauge
    x:Name="gauge"
    Minimum="0"
    Maximum="100"
    NeedleBrush="Transparent"
    ScaleTickBrush="White"
    ScaleBrush="White"
    ScaleWidth="20"                        
    TickBrush="White"
    TrailBrush="SeaGreen"
    ValueBrush="Orange"
    ValueStringFormat="N1">

所以我想创建几个styles,所以在我的Window.Resources

中创建它
<Style x:Key="GaugesStyle1" TargetType="{x:Type Controllers:Gauge}">
    <Setter Property="NeedleBrush" Value="Transparent"/>
    <Setter Property="ScaleTickBrush" Value="White"/>
    <Setter Property="ScaleBrush" Value="White"/>
    <Setter Property="ScaleWidth" Value="20"/>
    <Setter Property="TickBrush" Value="White"/>
    <Setter Property="TrailBrush" Value="SeaGreen"/>
    <Setter Property="ValueBrush" Value="Orange"/>
    <Setter Property="ValueStringFormat" Value="N1"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="HorizontalAlignment" Value="Center"/>
</Style>

并更改了我的control

<Controllers:Gauge
    x:Name="gauge"
    Minimum="0"
    Maximum="100"
    Style="{StaticResource GaugesStyle1}">

现在我看不到我的Gauge,它就消失了。 有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您的UserControl没有任何默认样式,因此您需要在窗口中定义的Style基于定义模板的第一个Style

这意味着您应该在某个全局资源字典中定义第一个Style(例如App.xaml)并为其指定x:Key。然后,您可以将第二种样式基于第一种样式:

<Style x:Key="GaugesStyle1" TargetType="{x:Type Controllers:Gauge}" BasedOn="{StaticResource theKeyOfTheFirstStyle}">
...

另一种选择是在GaugesStyle1中重新定义整个模板,或者创建一个实际具有默认样式的自定义控件。

Gauge导出您的Control课程,并将默认Style放在名为ResourceDictionary的名为Generic.xaml的{​​{1}} {你项目的根源。