WPF - 简单的UI框架 - 仪表盘
源码链接:
参考:
更新一: 功能导览模块新增Binding用法示例。
更新二:仪表盘效果实现。
Binding用法与ListBox的用法一致:
Xaml定义节点样式; .cs 文件中定义数据:
public class BaseRecord : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string prop) { if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } public class CatalogOfEffect: BaseRecord { private string _Name; public string Name { get { return _Name; } set { _Name = value; this.OnPropertyChanged("Name"); } } private bool _IsSelected; public bool IsSelected { get { return _IsSelected; } set { _IsSelected = value; this.OnPropertyChanged("IsSelected"); } } private string _Key; public string Key { get { return _Key; } set { _Key = value; } } }
引用样式:
指定数据源:
ObservableCollectionltCatalogs = new System.Collections.ObjectModel.ObservableCollection (); ltCatalogs.Add(new CatalogOfEffect() { Name = "淡入动效", Key="AnimFadeIn" }); ltCatalogs.Add(new CatalogOfEffect() { Name = "淡出动效", Key = "AnimFadeOut" }); ltCatalogs.Add(new CatalogOfEffect() { Name = "翻转动效", Key = "AnimFlip" }); ltCatalogs.Add(new CatalogOfEffect() { Name = "爆炸动效", Key = "AnimExpo" }); this.LmxBinding.ItemsSource = ltCatalogs;
扇形画面有很多码农通过Path、 ArcSegment等方式去构建。 Blend里面有Arc。 官方封装好的直接拿来用,省心省力。 用Path和ArcSegment的方式去实现,无非是用自己的方式再封装出一个Arc,其实没必要。
仪表盘的实现原理请参考Github上的源码。
仪表盘:代码
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:local="clr-namespace:WPFEffects.Modules.Chart.ClockChart" xmlns:BlendCom="http://schemas.microsoft.com/expression/2010/drawing" mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="480"> EndAngle="136" Stretch="None" ArcThickness="60"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,18.05"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,9.53"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,9.53"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,9.53"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,9.53"> Fill="White" HorizontalAlignment="Center" RenderTransformOrigin="0.5,9.53"> Foreground="White" FontSize="8" Margin="5"/> Foreground="White" FontSize="8" Margin="0,80,16,0"/> Foreground="White" FontSize="8" Margin="0,0,41,46"/> Foreground="White" FontSize="8" Margin="42,0,0,42"/> Foreground="White" FontSize="8" Margin="14,82,0,0"/> EndAngle="{Binding Path=DegreeAngle}" Fill="White" x:Name="ArcProxy" Stretch="None" ArcThickness="175" > EndAngle="135" Stretch="None" ArcThickness="10"> Margin="0,90,0,0" HorizontalAlignment="Center" Fill="#FF109B3A" Data="M0,180 L2,184 L4,180 L2 0 v4 z" RenderTransformOrigin="0.5,0.946"> VerticalAlignment="Bottom" Margin="0,0,0,130"/>
---------------------------------------------------------------------------------------------------------------
public partial class ClockSlave2View : UserControl
{
public double DegreeAngle
{
get { return (double)base.GetValue(DegreeAngleProperty); }
set { base.SetValue(DegreeAngleProperty, value); }
}
public static readonly DependencyProperty DegreeAngleProperty =
DependencyProperty.Register("DegreeAngle", typeof(double), typeof(ClockSlave2View),
new FrameworkPropertyMetadata(0d));
public ClockSlave2View()
{
InitializeComponent();
this.CreateNormalBorderMark();
this.DataContext = this;
this.Loaded += ClockSlave2View_Loaded;
this.Unloaded += ClockSlave2View_Unloaded;
}
private void ClockSlave2View_Unloaded(object sender, RoutedEventArgs e)
{
this.FreeSampleTimer();
}
private void ClockSlave2View_Loaded(object sender, RoutedEventArgs e)
{
this.CreateSampleTimer();
}
private void CreateNormalBorderMark()
{
this.GdEllipse.Children.Clear();
double dAngel = 270d / 100d;
for (int i = 1; i <= 100; i++)
{
if (i % 25 != 0)
{
Rectangle rect = new Rectangle();
rect.VerticalAlignment = VerticalAlignment.Top;
rect.HorizontalAlignment = HorizontalAlignment.Center;
rect.Fill = new SolidColorBrush(Colors.White);
rect.Width = 1;
rect.Height = 8;
rect.RenderTransformOrigin = new Point(0.5, 18.05);
TransformGroup transGroup = new TransformGroup();
RotateTransform rotate = new RotateTransform();
rotate.Angle = -135 + i * dAngel;
transGroup.Children.Add(rotate);
TranslateTransform translate = new TranslateTransform();
translate.X = -0.5;
transGroup.Children.Add(translate);
rect.RenderTransform = transGroup;
this.GdEllipse.Children.Add(rect);
}
}
}
private DispatcherTimer TimerSample;
private void CreateSampleTimer()
{
if(this.TimerSample == null)
{
this.TimerSample = new DispatcherTimer();
this.TimerSample.Tick += TimerSample_Tick;
this.TimerSample.Interval = TimeSpan.FromSeconds(1);
}
this.TimerSample.Start();
}
private void FreeSampleTimer()
{
if(this.TimerSample != null)
{
this.TimerSample.Stop();
this.TimerSample.Tick -= TimerSample_Tick;
}
this.TimerSample = null;
}
private void TimerSample_Tick(object sender, EventArgs e)
{
Random random = new Random();
int nData = random.Next(0, 100);
this.TbkValue.Text = nData + "";
double dAngle = -135d + 270d * nData / 100d;
DoubleAnimation anim = new DoubleAnimation(dAngle, TimeSpan.FromSeconds(0.3));
anim.EasingFunction = new ExponentialEase();
this.BeginAnimation(DegreeAngleProperty, anim);
}
}
原文:https://www.cnblogs.com/bruce1992/p/14934097.html