wpf 柱状图控件
<UserControl x:Class="wpf刻度线.TickBar" 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" xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" xmlns:ec="http://schemas.microsoft.com/expression/2010/controls" xmlns:local="clr-namespace:wpf刻度线" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Loaded="UserControl_Loaded"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="40" /> </Grid.RowDefinitions> <Label HorizontalAlignment="Left" VerticalAlignment="Center" Height="50" Content="{Binding Title, RelativeSource={RelativeSource AncestorType=UserControl}}" Foreground="{Binding LabelColor, RelativeSource={RelativeSource AncestorType=UserControl} }" FontFamily="微软雅黑"></Label> <Label HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,0,5" Foreground="#cc8800" FontFamily="微软雅黑" Content="XXXXXXXXXXXXXXXXXXXXXX" Grid.Row="1" /> <Border Width="80" HorizontalAlignment="Left" Grid.Row="2" Background="#24325f"> <Grid Margin="1,14,0,14" x:Name="mainGrid"> <!--具体的值填充的柱状图形--> <Grid x:Name="graphicGrid" Height="10" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Path Data="M40,0 L80,40 L0,40 z" Fill="#cc0663c2" Stretch="Fill" x:Name="path" /> <Border Grid.Row="1" Background="#cc0663c2" /> <Grid.RenderTransform> <RotateTransform Angle="0" x:Name="polygonRotateAngel" /> </Grid.RenderTransform> </Grid> <!--短刻度--> <ec:PathListBox Background="Transparent" x:Name="shortTicks" ItemsSource="{Binding ShortTicks,RelativeSource={RelativeSource AncestorType=UserControl}}" Focusable="False" FocusVisualStyle="{x:Null}"> <ec:PathListBox.ItemTemplate> <DataTemplate> <Rectangle Width="1" Height="48" Margin="0,0,0,49" Fill="#b5b5b5" Focusable="False" FocusVisualStyle="{x:Null}" /> <!--<Border Width="1" Height="48" Background="#b5b5b5" UseLayoutRounding="True" Margin="0,0,0,49" />--> </DataTemplate> </ec:PathListBox.ItemTemplate> <ec:PathListBox.LayoutPaths> <ec:LayoutPath Distribution="Even" Orientation="OrientToPath" SourceElement="{Binding ElementName=ShortTickPath}" > </ec:LayoutPath> </ec:PathListBox.LayoutPaths> </ec:PathListBox> <!-- 长刻度 --> <ec:PathListBox x:Name="LongTick" IsHitTestVisible="False" ItemsSource="{Binding LongTicks, RelativeSource={RelativeSource AncestorType=UserControl}}" Focusable="False" FocusVisualStyle="{x:Null}" > <ec:PathListBox.ItemTemplate> <DataTemplate> <Rectangle Width="48" Height="3" Margin="48,0,0,0" Fill="White" Focusable="False" FocusVisualStyle="{x:Null}" /> <!--<Border Width="3" Height="48" Background="White" SnapsToDevicePixels="True" UseLayoutRounding="True" Margin="0,0,0,49"> </Border>--> </DataTemplate> </ec:PathListBox.ItemTemplate> <ec:PathListBox.LayoutPaths> <ec:LayoutPath Distribution="Even" Orientation="None" SourceElement="{Binding ElementName=LongTickPath}" /> </ec:PathListBox.LayoutPaths> </ec:PathListBox> <!-- 刻度上显示的数字 --> <ec:PathListBox IsHitTestVisible="False" ItemsSource="{Binding TickMarks,RelativeSource={RelativeSource AncestorType=UserControl}}"> <ec:PathListBox.ItemTemplate> <DataTemplate> <TextBlock x:Name="tb" HorizontalAlignment="Left" Foreground="White" Text="{Binding}" RenderTransformOrigin="0,0" Margin="0,50,0,0"> <TextBlock.RenderTransform> <RotateTransform Angle="-90"/> </TextBlock.RenderTransform> </TextBlock> </DataTemplate> </ec:PathListBox.ItemTemplate> <ec:PathListBox.LayoutPaths> <ec:LayoutPath Distribution="Even" Orientation="OrientToPath" SourceElement="{Binding ElementName=NumberPath}" /> </ec:PathListBox.LayoutPaths> </ec:PathListBox> <Path x:Name="LongTickPath" Data="M0,0 v1" VerticalAlignment="Top" HorizontalAlignment="Right" Stretch="Fill" Fill="Red" Stroke="Red" StrokeThickness="2" Grid.RowSpan="2" Margin="0,0" Focusable="False" FocusVisualStyle="{x:Null}" /> <Path x:Name="ShortTickPath" Data="M0,0 V1" VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="Fill" Grid.RowSpan="2" Margin="0,0" Focusable="False" FocusVisualStyle="{x:Null}" /> <Path x:Name="NumberPath" Data="M0,0 V1" Margin="45,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Center" Stretch="Fill" Grid.RowSpan="2" Focusable="False" FocusVisualStyle="{x:Null}" Stroke="Yellow" StrokeThickness="1"/> </Grid> </Border> <StackPanel Grid.Row="3" Orientation="Horizontal"> <TextBox Width="90" Height="35" IsReadOnly="True" Foreground="{Binding TextboxColor,RelativeSource={RelativeSource AncestorType=UserControl}}" VerticalAlignment="Center" Text="{ Binding CurrentValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Control}}" /> <Label VerticalAlignment="Center" Content="km" Foreground="{Binding LabelColor, RelativeSource={RelativeSource AncestorType=UserControl}}"></Label> </StackPanel> </Grid> </UserControl>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace wpf刻度线 { /// <summary> /// TickBar.xaml 的交互逻辑 /// </summary> public partial class TickBar : UserControl { public TickBar() { InitializeComponent(); } public List<string> TickMarks { get { return (List<string>)GetValue(TickMarksProperty); } set { SetValue(TickMarksProperty, value); } } // Using a DependencyProperty as the backing store for TickMarks. This enables animation, styling, binding, etc... public static readonly DependencyProperty TickMarksProperty = DependencyProperty.Register("TickMarks", typeof(List<string>), typeof(TickBar), new PropertyMetadata(null)); public List<object> LongTicks { get { return (List<object>)GetValue(LongTicksProperty); } set { SetValue(LongTicksProperty, value); } } // Using a DependencyProperty as the backing store for LongTicks. This enables animation, styling, binding, etc... public static readonly DependencyProperty LongTicksProperty = DependencyProperty.Register("LongTicks", typeof(List<object>), typeof(TickBar), new PropertyMetadata(null)); public List<object> ShortTicks { get { return (List<object>)GetValue(ShortTicksProperty); } set { SetValue(ShortTicksProperty, value); } } // Using a DependencyProperty as the backing store for ShortTicks. This enables animation, styling, binding, etc... public static readonly DependencyProperty ShortTicksProperty = DependencyProperty.Register("ShortTicks", typeof(List<object>), typeof(TickBar), new PropertyMetadata(null)); public double CurrentValue { get { return (double)GetValue(CurrentValueProperty); } set { SetValue(CurrentValueProperty, value); } } // Using a DependencyProperty as the backing store for CurrentValue. This enables animation, styling, binding, etc... public static readonly DependencyProperty CurrentValueProperty = DependencyProperty.Register("CurrentValue", typeof(double), typeof(TickBar), new PropertyMetadata(0.0, CurrentValueChangeCallback)); private static void CurrentValueChangeCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { TickBar c = d as TickBar; UpdateUICurrentvalue((double)e.NewValue, c); } private static void UpdateUICurrentvalue(double currentValue, TickBar c) { if (c.mainGrid.ActualHeight == 0) { return; } if (currentValue > 0) { c.polygonRotateAngel.Angle = 0; double totalValue = c.MaxValue - c.MinValue; //计算显示图形位置 double top = (c.MaxValue - currentValue) * c.mainGrid.ActualHeight / totalValue; //计算显示图形大小 double height = currentValue * c.mainGrid.ActualHeight / totalValue; c.graphicGrid.Margin = new Thickness(0, top, 0, 0); if (height > 40) { c.graphicGrid.Height = height; } else { c.graphicGrid.Height = c.path.Height = height; } } else { c.polygonRotateAngel.Angle = 180; double totalValue = c.MaxValue - c.MinValue; //计算显示图形位置 double top = (c.MaxValue) * c.mainGrid.ActualHeight / totalValue; //计算显示图形大小 double height = -currentValue * c.mainGrid.ActualHeight / totalValue; c.graphicGrid.Margin = new Thickness(0, top, 0, 0); if (height > 40) { c.graphicGrid.Height = height; } else { c.graphicGrid.Height = c.path.Height = height; } } } public SolidColorBrush LabelColor { get { return (SolidColorBrush)GetValue(LabelColorProperty); } set { SetValue(LabelColorProperty, value); } } // Using a DependencyProperty as the backing store for LabelColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty LabelColorProperty = DependencyProperty.Register("LabelColor", typeof(SolidColorBrush), typeof(TickBar), new PropertyMetadata(Brushes.Black)); public SolidColorBrush TextboxColor { get { return (SolidColorBrush)GetValue(TextboxColorProperty); } set { SetValue(TextboxColorProperty, value); } } // Using a DependencyProperty as the backing store for TextboxColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty TextboxColorProperty = DependencyProperty.Register("TextboxColor", typeof(SolidColorBrush), typeof(TickBar), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(214, 214, 214)))); public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(TickBar), new PropertyMetadata("")); public double MaxValue { get { return (double)GetValue(MaxValueProperty); } set { SetValue(MaxValueProperty, value); } } // Using a DependencyProperty as the backing store for MaxValue. This enables animation, styling, binding, etc... public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(TickBar), new PropertyMetadata(30d)); public double MinValue { get { return (double)GetValue(MinValueProperty); } set { SetValue(MinValueProperty, value); } } // Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc... public static readonly DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(TickBar), new PropertyMetadata(-10d)); private void UserControl_Loaded(object sender, RoutedEventArgs e) { //短刻度 List<object> shortticks = new List<object>(); for (int i = 0; i < 50; i++) { shortticks.Add(new object()); } ShortTicks = shortticks; //显示刻度文字 List<string> numbers = new List<string>(); //长刻度 List<object> longticks = new List<object>(); for (int i = 0; i < 5; i++) { //计算长度信息,等比例地减去间隔值 string tickInfo = (MaxValue - i * (MaxValue - MinValue) / 4).ToString(); numbers.Add(tickInfo + new string('&', i + 1)); longticks.Add(new object()); } LongTicks = longticks; TickMarks = numbers; UpdateUICurrentvalue(CurrentValue, this); } } }
效果图