WPF - 简单的UI框架 - 仪表盘

源码链接:https://github.com/DuelWithSelf/WPFEffects

 参考:https://www.cnblogs.com/duel/p/duel_clock.html

更新一: 功能导览模块新增Binding用法示例。

WPF - 简单的UI框架 - 仪表盘

 

更新二:仪表盘效果实现。

WPF - 简单的UI框架 - 仪表盘

Binding用法与ListBox的用法一致:

Xaml定义节点样式; .cs 文件中定义数据:

WPF - 简单的UI框架 - 仪表盘
 <DataTemplate x:Key="ListMenuBox.ItemTemplate" DataType="{x:Type local:CatalogOfEffect}">
            <Border x:Name="BdrNavItem" Background="Transparent" Height="30"
                    MouseLeftButtonUp="BdrNavItem_MouseLeftButtonUp">
                <TextBlock Margin="60,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center"
                           Foreground="White" Text="{Binding Path=Name, Mode=TwoWay}"/>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
                    <Setter TargetName="BdrNavItem" Property="Background" 
                            Value="{StaticResource ColorBrush.LightWhite}"/>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
WPF - 简单的UI框架 - 仪表盘
WPF - 简单的UI框架 - 仪表盘
 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; }
        }
    }
WPF - 简单的UI框架 - 仪表盘

引用样式:

 <CustomFrms:ListMenuBox 
                                x:Name="LmxBinding" Text="Binding示例" 
                                IconData="{StaticResource PathData.TagSolid}"
                                ItemTemplate="{StaticResource ListMenuBox.ItemTemplate}"/>

指定数据源:

WPF - 简单的UI框架 - 仪表盘
  ObservableCollection<CatalogOfEffect> ltCatalogs = new System.Collections.ObjectModel.ObservableCollection<CatalogOfEffect>();
            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;
WPF - 简单的UI框架 - 仪表盘

扇形画面有很多码农通过Path、 ArcSegment等方式去构建。 Blend里面有Arc。 官方封装好的直接拿来用,省心省力。  用Path和ArcSegment的方式去实现,无非是用自己的方式再封装出一个Arc,其实没必要。

仪表盘的实现原理请参考Github上的源码。

仪表盘:代码

 

<UserControl x:Class="WPFEffects.Modules.Chart.ClockChart.ClockSlave2View"

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

    <Grid Width="370" Height="370">

 

        <BlendCom:Arc Width="340" Height="340" StartAngle="-136" 

                      EndAngle="136" Stretch="None" ArcThickness="60">

            <BlendCom:Arc.Fill>

                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                    <GradientStop Color="#3300A2FF" Offset="0"/>

                    <GradientStop Color="#005ED3FF" Offset="1"/>

                </LinearGradientBrush>

            </BlendCom:Arc.Fill>

        </BlendCom:Arc>

        <Grid x:Name="GdEllipse" Width="290" Height="290">

            <Rectangle Width="1" Height="8" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,18.05">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="2.7"/>

                        <TranslateTransform X="-0.5"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

        </Grid>

        <Grid x:Name="GdEllipse1" Width="306" Height="306">

            <Rectangle Width="1" Height="16" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,9.53">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="0"/>

                        <TranslateTransform X="-0.5" Y="0"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

            <Rectangle Width="1" Height="16" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,9.53">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="67.5"/>

                        <TranslateTransform X="-0.5" Y="0"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

            <Rectangle Width="1" Height="16" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,9.53">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="135"/>

                        <TranslateTransform X="-0.5" Y="0"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

            <Rectangle Width="1" Height="16" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,9.53">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="-67.5"/>

                        <TranslateTransform X="-0.5" Y="0"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

            <Rectangle Width="1" Height="16" VerticalAlignment="Top"

                       Fill="White" HorizontalAlignment="Center" 

                       RenderTransformOrigin="0.5,9.53">

                <Rectangle.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="-135"/>

                        <TranslateTransform X="-0.5" Y="0"/>

                    </TransformGroup>

                </Rectangle.RenderTransform>

            </Rectangle>

        </Grid>

 

        <Grid Width="270" Height="270">

            <TextBlock Text="50" HorizontalAlignment="Center" VerticalAlignment="Top" 

                           Foreground="White" FontSize="8" Margin="5"/>

            <TextBlock Text="75" HorizontalAlignment="Right" VerticalAlignment="Top" 

                           Foreground="White" FontSize="8" Margin="0,80,16,0"/>

            <TextBlock Text="100" HorizontalAlignment="Right" VerticalAlignment="Bottom" 

                           Foreground="White" FontSize="8" Margin="0,0,41,46"/>

            <TextBlock Text="0" HorizontalAlignment="Left" VerticalAlignment="Bottom" 

                           Foreground="White" FontSize="8" Margin="42,0,0,42"/>

            <TextBlock Text="25" HorizontalAlignment="Left" VerticalAlignment="Top" 

                        Foreground="White" FontSize="8" Margin="14,82,0,0"/>

        </Grid>

 

        <Grid Opacity="0">

            <Grid Width="370" Height="370" x:Name="ClipProxy">

                <Grid Background="Transparent"></Grid>

                <BlendCom:Arc Width="370" Height="370" StartAngle="-180" 

                          EndAngle="{Binding Path=DegreeAngle}" Fill="White" 

                            x:Name="ArcProxy"  Stretch="None"

                          ArcThickness="175" >

                </BlendCom:Arc>

            </Grid>

        </Grid>

 

        <Grid>

            <Border Width="370" Height="370" Background="Transparent">

                <Border.OpacityMask>

                    <VisualBrush Visual="{Binding ElementName=ClipProxy}"/>

                </Border.OpacityMask>

                <BlendCom:Arc Width="370" Height="370" StartAngle="-135" 

                      EndAngle="135" Stretch="None" ArcThickness="10">

                    <BlendCom:Arc.Fill>

                        <LinearGradientBrush EndPoint="1,1" StartPoint="0,1">

                            <GradientStop Color="#FF31FF10" Offset="0.01"/>

                            <GradientStop Color="#FF760F0F" Offset="1"/>

                            <GradientStop Color="#FFE6BF6B" Offset="0.22"/>

                            <GradientStop Color="#FFF7876E" Offset="0.444"/>

                            <GradientStop Color="#FFE22E21" Offset="0.702"/>

                        </LinearGradientBrush>

                    </BlendCom:Arc.Fill>

                </BlendCom:Arc>

            </Border>

 

            <Path Stretch="Fill" Width="4" Height="95" VerticalAlignment="Top"

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

                <Path.RenderTransform>

                    <TransformGroup>

                        <ScaleTransform/>

                        <SkewTransform/>

                        <RotateTransform Angle="{Binding Path=DegreeAngle}"/>

                        <TranslateTransform/>

                    </TransformGroup>

                </Path.RenderTransform>

                <Path.Effect>

                    <DropShadowEffect Color="White" Opacity="0.5" ShadowDepth="0" BlurRadius="8"/>

                </Path.Effect>

            </Path>

            <TextBlock x:Name="TbkValue" Text="0.0" Foreground="White" HorizontalAlignment="Center"

                       VerticalAlignment="Bottom" Margin="0,0,0,130"/>

        </Grid>

        

      

    </Grid>

</UserControl>

 

---------------------------------------------------------------------------------------------------------------

 

 

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

        }

    }

 

WPF - 简单的UI框架 - 仪表盘

上一篇:ASP.NET Web API


下一篇:Photoshop调出韩式婚纱照梦幻童话效果