2

[WPF] 使用 HandyControl 的 CirclePanel 画出表盘刻度

 1 year ago
source link: https://www.cnblogs.com/dino623/p/16471012.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1. 前言#

最近需要一个 WPF 的表盘控件,之前 Cyril-hcj 写过一篇不错的博客 《WPF在圆上画出刻度线》,里面介绍了一些原理及详细实现的代码:

double radius = BackEllipse.Width / 2;
double min = 0; double max = 100;
double step = 360.0 / (max - min);
for (int i = 0; i < max - min; i++)
{
    Line lineScale = new Line
    {
        X1 = ((radius - 20) * Math.Cos(i * step * Math.PI / 180)) + radius,
        Y1 = ((radius - 20) * Math.Sin(i * step * Math.PI / 180)) + radius,
        X2 = (radius * Math.Cos(i * step * Math.PI / 180)) + radius,
        Y2 = (radius * Math.Sin(i * step * Math.PI / 180)) + radius,
        Stroke = Brushes.Red,
        StrokeThickness = 2
    };

    MainCanvas.Children.Add(lineScale);
}

我本来想直接参考这篇文章的代码封装成一个控件,但我用得不多封装起来又麻烦,索性考虑用 ItemsControl 实现还比较方便些。

2. 使用 CirclePanel 实现#

既然要用 ItemsControl,那首先要有个集合作为它的 ItemsSource。在 XAML 中可以用以下方式创建一个集合:

<x:Array x:Key="AuthorList" Type="{x:Type sys:String}">
    <sys:String>Mahesh Chand</sys:String>
    <sys:String>Praveen Kumar</sys:String>
    <sys:String>Raj Beniwal</sys:String>
    <sys:String>Neel Beniwal</sys:String>
    <sys:String>Sam Hobbs</sys:String>
</x:Array>

不过也可以不这么大费周章,在 .NET 中 string 也是一个集合,
可以用作 ItemsControl 的 ItemsSource。但在 Xaml 上直接写 ItemsSource="somestring"` 会报错,可以用 ContentControl 包装一下,写成这样:

<ContentControl Content="111111111111">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Rectangle Width="10"
                                   Height="3"
                                   Fill="#383838" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>

这样 UI 上就会重复创建 12 个 Rectangle,然后设置 ItemsControl 的 ItemsPanel,让这些 Rectangle 按着圆形布局。这里我使用了 HandyControl 的 CirclePanel,这个 Panel 用起来十分简单,它会自动将 Children 在圆形上等距分布:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <hc:CirclePanel Diameter="310" />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

顺便一提,HandyControl 的 Nuget 地址为:https://www.nuget.org/packages/HandyControl/3.3.0?_src=template

最后再添加一些边框和内阴影,一个简单的表盘就完成了。

38937-20220712174438602-1754352293.png

3. 用 DataTrigger 实现不同的指针#

上面的表盘还是做得太朴素了,我们可以用 DataTrigger 让它变得更复杂些。首先改变 ItemsSource 的内容,让它变成 60 个指针。反正只是 60 个,也没多复杂,复制粘贴几次就有了:

<ContentControl Content="100001000010000100001000010000100001000010000100001000010000">

然后设置 DataTrigger,在 Item 的内容等于 1 时指针变粗些:

<DataTemplate>
    <Rectangle x:Name="Tick"
               Width="10"
               Height="2"
               Fill="#383838" />
    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding}" Value="1">
            <Setter TargetName="Tick" Property="Height" Value="5" />
            <Setter TargetName="Tick" Property="Width" Value="16" />
            <Setter TargetName="Tick" Property="Margin" Value="0,0,3,0" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

38937-20220712174446445-1770463436.png

这样看起来就和真的表盘差不多了。

4. 用 OpacityMask 实现方形表盘#

这次更进一步实现一个方形的表盘,首先将 CirclePanel 的尺寸变大,然后加长刻度线:

38937-20220712174457805-1895591029.png

然后在它的背后藏一个 Border,用它作为刻度线的 OpacityMask,这样就完成了一个方形表盘:

<Border x:Name="Border"
        Width="340"
        Height="340"
        BorderBrush="White"
        BorderThickness="16" />
<ContentControl Style="{StaticResource ClockControl2}">
    <ContentControl Margin="-100" Content="100001000010000100001000010000100001000010000100001000010000">
        <ContentControl.OpacityMask>
            <VisualBrush Stretch="None" Visual="{Binding ElementName=Border}" />
        </ContentControl.OpacityMask>

38937-20220712174503327-2058100248.png

5. 用 ArcPanel 实现仪表盘#

CirclePanel 虽然很好用,可惜的是不能实现弧形布局,于是我又另外找了 HeBianGu 的 ArcPanel 来实现仪表板,用它替换掉 CirclePanel 即可实现弧形布局的刻度线:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <h:ArcPanel Width="200"
                    Height="200"
                    AngleToCenter="True"
                    EndAngle="-30"
                    StartAngle="210" />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

38937-20220712174510543-962159921.png

5. 最后#

这篇文章介绍了如何实现表盘刻度,基本都是用别人的 Panel 实现布局,我自己反而没出什么力,感谢两位大佬实现的优秀 Panel。

顺便一提,也可以用 Ellipe 配合 StrokeDashArray 简单做出这种效果,只是如果太粗的指针会看得出来是个扇形,不是矩形,而且还不够灵活。

38937-20220712174516682-1742041596.png

源码:https://github.com/DinoChan/wpf_design_and_animation_lab


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK