通过XAML进行静态属性绑定无法使用自定义控制器

时间:2017-07-11 10:01:29

标签: wpf binding gauge

所以我有Gauge

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

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

所以我的这个类有static属性来实现INotifyPropertyChanged

我想做的就是更新Gauge中的xaml值,而不是通过后面的代码:

<Controllers:Gauge
    x:Name="gauge"
    Value="{Binding Path=(Data.MyStaticPropert)}"
    Minimum="0"
    Maximum="100"/>

这里的问题是如果我拿这个代码:

"{Binding Path=(Data.MyStaticPropert)}"

并且放入简单的Label Content属性内部,这项工作很好但是在我的Gauge Value属性中 - 没有! (我没有添加所有代码的原因是Label

有什么建议吗?

0 个答案:

没有答案