大数跨境
0
0

WPF 实现 3D 导航栏(鼠标交互、滚动布局与跨版本支持)

WPF 实现 3D 导航栏(鼠标交互、滚动布局与跨版本支持) DotNet技术匠
2025-11-07
0
导读:WPF 实现 3D 导航

  WPF 实现 3D 导航

  • 框架支持.NET4 至 .NET8

  • Visual Studio 2022;

  • AnimationNavigationBar3D 带有 3D 效果的导航栏控件的样式。包含多个 AnimationNavigationBar3DItem ,通过 UniformGrid 进行排列,超出显示区域的项可以滚动查看。

  • AnimationNavigationBar3DItem 继承 ListBboxItem 是 3D 导航栏中的每个项。使用 Viewport3D 来创建一个具有 3D 效果的容器,当鼠标移入或移出时,旋转动画来改变项的外观。它包含一个正面 Background 和一个背面 ContentBack ,可以显示不同的内容。使用可以根据需要自定义内容,如果在每个项中只设置了正面内容而没有设置背面内容,那么背面会自动克隆 GetXmlReader 并显示与正面相同的内容。

  • GetXmlReader 用于通过将 UIElement 对象转换为 XML 字符串,再将其转换回 UIElement 对象,实现对 UIElement 对象的克隆。

1)新增 AnimationNavigationBar3D.cs 代码如下:

    public classAnimationNavigationBar3D : ListBox
    {
        static AnimationNavigationBar3D()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimationNavigationBar3D),
                new FrameworkPropertyMetadata(typeof(AnimationNavigationBar3D)));
        }
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is AnimationNavigationBar3DItem;
        }
        protected override DependencyObject GetContainerForItemOverride()
        {
            returnnew AnimationNavigationBar3DItem();
        }
    }

2)新增 AnimationNavigationBar3DItem.cs 代码如下:

    public classAnimationNavigationBar3DItem : ListBoxItem
    {
        publicstaticreadonly DependencyProperty FillProperty =
            DependencyProperty.Register("Fill"typeof(Brush), typeof(AnimationNavigationBar3DItem),
                new PropertyMetadata(null));

        publicstaticreadonly DependencyProperty ContentBackProperty =
            DependencyProperty.Register("ContentBack"typeof(object), typeof(AnimationNavigationBar3DItem),
                new PropertyMetadata(null));

        static AnimationNavigationBar3DItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimationNavigationBar3DItem),
                new FrameworkPropertyMetadata(typeof(AnimationNavigationBar3DItem)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (ContentBack == null
                ContentBack = ControlsHelper.GetXmlReader(Content);
        }

        /// <summary>
        ///  Color fore
        /// </summary>
        public Brush Fill
        {
            get => (Brush)GetValue(FillProperty);
            set => SetValue(FillProperty, value);
        }

        /// <summary>
        ///  The content after the mouse is moved in
        /// </summary>
        publicobject ContentBack
        {
            get => (object)GetValue(ContentBackProperty);
            set => SetValue(ContentBackProperty, value);
        }
    }

3)新增 AnimationNavigationBar3D.xaml 代码如下:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:WPFDevelopers.Controls">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml" />
        <ResourceDictionary Source="Basic/Animations.xaml" />
    </ResourceDictionary.MergedDictionaries>
    <Style
        x:Key="WD.AnimationNavigationBar3DItem"
        BasedOn="{StaticResource WD.ControlBasicStyle}"
        TargetType="{x:Type controls:AnimationNavigationBar3DItem}">

        <Setter Property="Width" Value="80" />
        <Setter Property="Height" Value="80" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Foreground" Value="{DynamicResource WD.WindowForegroundColorBrush}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:AnimationNavigationBar3DItem}">
                    <Viewport3D Width="{TemplateBinding Height}" Height="{TemplateBinding Width}">
                        <Viewport3D.Triggers>
                            <EventTrigger RoutedEvent="MouseEnter">
                                <BeginStoryboard>
                                    <Storyboard Storyboard.TargetName="axis3d" Storyboard.TargetProperty="Angle">
                                        <DoubleAnimation
                                            EasingFunction="{StaticResource WD.CubicEaseInOut}"
                                            To="90"
                                            Duration="00:00:1" />

                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                            <EventTrigger RoutedEvent="MouseLeave">
                                <BeginStoryboard>
                                    <Storyboard Storyboard.TargetName="axis3d" Storyboard.TargetProperty="Angle">
                                        <DoubleAnimation
                                            EasingFunction="{StaticResource WD.CubicEaseInOut}"
                                            To="0"
                                            Duration="00:00:1" />

                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </Viewport3D.Triggers>
                        <Viewport3D.Camera>
                            <OrthographicCamera
                                LookDirection="0,0,-100"
                                Position="0,0,100"
                                UpDirection="0,1,0" />

                        </Viewport3D.Camera>
                        <Viewport3D.Children>
                            <ModelVisual3D>
                                <ModelVisual3D.Content>
                                    <AmbientLight Color="{DynamicResource WD.BackgroundColor}" />
                                </ModelVisual3D.Content>
                            </ModelVisual3D>
                            <ContainerUIElement3D>
                                <ContainerUIElement3D.Transform>
                                    <RotateTransform3D>
                                        <RotateTransform3D.Rotation>
                                            <AxisAngleRotation3D
                                                x:Name="axis3d"
                                                Angle="0"
                                                Axis="1 0 0" />

                                        </RotateTransform3D.Rotation>
                                    </RotateTransform3D>
                                </ContainerUIElement3D.Transform>
                                <Viewport2DVisual3D>
                                    <Viewport2DVisual3D.Material>
                                        <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />
                                    </Viewport2DVisual3D.Material>
                                    <Viewport2DVisual3D.Geometry>
                                        <MeshGeometry3D
                                            Positions="-1,1,1    -1,-1,1   1,-1,1    1,1,1"
                                            TextureCoordinates="0,0   0,1     1,1  1,0"
                                            TriangleIndices="0 1 2 0 2 3" />

                                    </Viewport2DVisual3D.Geometry>
                                    <Border
                                        Width="110"
                                        Height="110"
                                        Background="{TemplateBinding Background}"
                                        CornerRadius="0,0,0,0">

                                        <ContentPresenter
                                            x:Name="PART_ContentPresenter"
                                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                            TextElement.Foreground="{TemplateBinding Foreground}" />

                                    </Border>
                                </Viewport2DVisual3D>
                                <Viewport2DVisual3D>
                                    <Viewport2DVisual3D.Material>
                                        <DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" />
                                    </Viewport2DVisual3D.Material>
                                    <Viewport2DVisual3D.Geometry>
                                        <MeshGeometry3D
                                            Positions="-1,1,1  1,1,1   1,1,-1   -1,1,-1"
                                            TextureCoordinates="0,0   0,1   1,1  1,0"
                                            TriangleIndices="0 1 2 0 2 3" />

                                    </Viewport2DVisual3D.Geometry>
                                    <Border
                                        Width="110"
                                        Height="110"
                                        Background="{TemplateBinding Fill}"
                                        CornerRadius="0,0,0,0"
                                        RenderTransformOrigin="0.5,0.5">

                                        <Border.RenderTransform>
                                            <TransformGroup>
                                                <RotateTransform Angle="90" />
                                            </TransformGroup>
                                        </Border.RenderTransform>
                                        <ContentPresenter
                                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                            Content="{Binding ContentBack, RelativeSource={RelativeSource AncestorType={x:Type controls:AnimationNavigationBar3DItem}}}"
                                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                            TextElement.Foreground="{TemplateBinding Foreground}" />

                                    </Border>
                                </Viewport2DVisual3D>
                            </ContainerUIElement3D>
                        </Viewport3D.Children>
                    </Viewport3D>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    
</Style>
    <Style
        x:Key="WD.AnimationNavigationBar3D"
        BasedOn="{StaticResource WD.ControlBasicStyle}"
        TargetType="{x:Type controls:AnimationNavigationBar3D}">

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:AnimationNavigationBar3D}">
                    <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                        UseLayoutRounding="{TemplateBinding UseLayoutRounding}">

                        <ScrollViewer VerticalScrollBarVisibility="Auto">
                            <ItemsPresenter />
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="{Binding Items.Count, RelativeSource={RelativeSource AncestorType={x:Type controls:AnimationNavigationBar3D}}}" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    
</Style>
    <Style BasedOn="{StaticResource WD.AnimationNavigationBar3DItem}" TargetType="{x:Type controls:AnimationNavigationBar3DItem}" />
    <Style BasedOn="{StaticResource WD.AnimationNavigationBar3D}" TargetType="{x:Type controls:AnimationNavigationBar3D}" />
</ResourceDictionary>

4)新增 GetXmlReader.cs 代码如下:

 public static object GetXmlReader(object Content)
 {
     var originalContent = Content as UIElement;
     string contentXaml = XamlWriter.Save(originalContent);
     using (StringReader stringReader = new StringReader(contentXaml))
     {
         using (XmlReader xmlReader = XmlReader.Create(stringReader))
         {
             object clonedContent = XamlReader.Load(xmlReader);

             if (clonedContent is UIElement clonedElement)
             {
                 return clonedElement;
             }
         }
     }
     returnnull;
 }

5)新增 AnimationNavigationBar3D.xaml 示例代码如下:

<wd:AnimationNavigationBar3D VerticalAlignment="Bottom">
    <wd:AnimationNavigationBar3DItem Background="#E21854" Fill="#FD3574">
        <StackPanel VerticalAlignment="Center">
            <Path
                Width="40"
                Height="40"
                Data="{StaticResource WD.SmileyOutlineGeometry}"
                Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                Stretch="Uniform" />

            <TextBlock HorizontalAlignment="Center" Text="Emoji" />
        </StackPanel>
    </wd:AnimationNavigationBar3DItem>
    <wd:AnimationNavigationBar3DItem Background="#41A545" Fill="#5EECA6">
        <StackPanel VerticalAlignment="Center">
            <Path
                Width="40"
                Height="40"
                Data="{StaticResource WD.BusGeometry}"
                Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                Stretch="Uniform" />

            <TextBlock HorizontalAlignment="Center" Text="Bus" />
        </StackPanel>
    </wd:AnimationNavigationBar3DItem>
    <wd:AnimationNavigationBar3DItem Background="#0A58F0" Fill="#3A7DFE">
        <StackPanel VerticalAlignment="Center">
            <Path
                Width="40"
                Height="40"
                Data="{StaticResource WD.FriendGeometry}"
                Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                Stretch="Uniform" />

            <TextBlock HorizontalAlignment="Center" Text="Friend" />
        </StackPanel>
    </wd:AnimationNavigationBar3DItem>
    <wd:AnimationNavigationBar3DItem Background="#5F0574" Fill="#8E1FA4">
        <StackPanel VerticalAlignment="Center">
            <Path
                Width="40"
                Height="40"
                Data="{StaticResource WD.AlarmClockGeometry}"
                Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                Stretch="Uniform" />

            <TextBlock HorizontalAlignment="Center" Text="Clock" />
        </StackPanel>
    </wd:AnimationNavigationBar3DItem>
    <wd:AnimationNavigationBar3DItem Background="#1F0355" Fill="#5B31AD">
        <wd:AnimationNavigationBar3DItem.Content>
            <StackPanel VerticalAlignment="Center">
                <Path
                    Width="40"
                    Height="40"
                    Data="{StaticResource WD.BuildingRegularGeometry}"
                    Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                    Stretch="Uniform" />

                <TextBlock HorizontalAlignment="Center" Text="Regular" />
            </StackPanel>
        </wd:AnimationNavigationBar3DItem.Content>
        <wd:AnimationNavigationBar3DItem.ContentBack>
            <StackPanel VerticalAlignment="Center">
                <Path
                    Width="40"
                    Height="40"
                    Data="{StaticResource WD.BuildingRegularGeometry}"
                    Fill="{DynamicResource WD.WindowForegroundColorBrush}"
                    Stretch="Uniform" />

                <TextBlock HorizontalAlignment="Center" Text="建筑" />
            </StackPanel>
        </wd:AnimationNavigationBar3DItem.ContentBack>
    </wd:AnimationNavigationBar3DItem>
</wd:AnimationNavigationBar3D>
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。也可以加入微信公众号[DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

作者:小码编匠

出处:gitee.com/smallcore/DotNetCore
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!



END



方便大家交流、资源共享和共同成长
纯技术交流群,需要加入的小伙伴请扫码,并备注加群



推荐阅读






WPF 高颜值工业上位机快速开发框架 
WinForm +SQLite 开发的高效PLC数据采集系统
C# 开发的串口固件传输工具 支持OTA升级
C# 实现海康相机 + PLC + 数据库的工业通信集成
WinForm 无线环境监控上位机系统设计与实现
工业自动化实战:C# 实现 Basler 相机图像采集系统
一款面向对象的开源 WPF TreeView 树控件
C# 基于机器视觉的液体颜色识别系统

C# 实现 GB28181标准与流媒体推流的完整指南

C# 访客身份核验实战:集成虹软人脸识别与华视身份证阅读器

.NET 8 + ABP-VNext 企业级权限管理系统

基于 WPF 的无人值守地磅系统:车牌识别+设备联动自动称重

基于 .NET + Vue 3 的线路图绘制系统实战(含源码)

WPF 版简易 SIP 服务器:高效向 GB28181 摄像头发送直播请求

WinForm 下基于策略与工厂模式的 PLC 数据采集与监控系统

C# 开发工业级温湿度上位机:实时采集与存储

面向工业自动化的 WPF PLC 风格上位机开发框架

C# 写的一个开源免费的OPC UA网关,支持西门子PLC

WinForm + FFmpeg 开发的轻量级视频压缩工具

.NET 8 + Avalonia 跨平台简易校园信息管理系统的开发实战

Windows 服务可视化管理器:安装、启停、定时全搞定

C# + WPF + SuperSocket 开发面向工业自动化的 MES 系统

告别服务宕机,C# 看门狗守护你的 WinForm 与 Windows 服务

.NET 一款高效跨平台的自动更新工具(差异更新+热修复+自动升级)

WinForm 工业流量计串口调试助手:支持Modbus双协议的智能调试工具

面向工厂自动化的智能语音播报方案(基于.NET Windows服务)

基于 WPF + Prism 的工业自动化监控系统开源实践

工业自动化UI太难做?WPF 这套工业级控件方案真香(附源码)

工业自动化 WPF + Halcon 的模块化机器视觉解决方案

C# 开源视觉与运动控制集成平台,模块化设计赋能工业自动化

开源福利!八款 WPF + HandyControl 工业管理系统源码全公开

WinForm + Win32 API 自定义无边框窗口实战(工业软件必备)

WPF + MVVM架构的轻量级视频播放器实现

基于 HslCommunication 的多端同步PLC远程监控系统

C# + Vue 面向工业场景的实时数据采集与监控平台

WinForm 数据采集实战:从串口通信到MES对接的轻量化解决方案

一个拒绝过度设计的 .NET 快速开发框架:开箱即用,专注"干活"

C# 工业视觉全流程实战:模板匹配、胶钉定位与下位机通信
WPF 通信控制台:功能丰富、界面美观的上位机开发实战
拿来就用!一个基于 .NET 6 + WPF 的开源数据大屏模板

WinForm + SunnyUI  与 MQTTnet 实现智能可视化的火警联动大屏系统

工业自动化实战:基于 .NET + ModBus RTU协议的称重机开发

WinForm 基于 SunnyUI+ PCLSharp 的机器视觉焊接系统

.NET 9 + WPF + Halcon 构建工业视觉流程框架:从架构设计到落地实践

WinForm 高分屏适配难题?一款强大的控件自适应缩放工具

开源轻量的 WinForm 图片处理工具,提取主色调、应用滤镜、重新上色
基于 .NET 6 + OpenCVSharp 的跨平台工业视觉图像分析工具
WinForm 框架下的工控领域视觉检测
基于 .NET 8 + React 的轻量高效库存管理系统(前后端分离)
WPF 实时工业监控大屏:ModBus协议集成与无边框动态可视化方案
图形化操作 Windows 服务?这个开源小工具做到了
.NET 9.0 一个可复用 WPF 界面框架
手把手教会设计 WinForm 高DPI兼容程序,告别字体模糊与控件乱飞

WPF + MVVM 自助式检验报告打印机的多框架实现

为什么 .NET 内存占用非常大?

C# 部署 Yolov8 全攻略:OpenVINO 与 TensorRT  双引擎加速
WPF 一款通用的嵌入式测控上位机(灵活配置免重复)
干货推荐:五款功能强大的 .NET 开源工作流系统,拿来即用
全栈 .NET 低代码引擎:权限、工作流、API动态生成,开源即用
一款基于 .NET 的轻量级 ERP 进销存系统:扫码入库、订单变标签,直达发货
.NET 8 + Vue 3 的智能工厂 MES 快速开发框架:设备监控、数据大屏全覆盖
.NET 9 + React 基于 DDD架构的动态路由 + RBAC权限实战
基于 SunnyUI 的企业级 WinForm 快速开发框架,开箱即用!
免硬件方案!基于.NET 的摄像头扫码工具(支持回车/连续扫描)
工业级 MES 系统开发 WPF + MVVM 从入门到实战(全源码/收藏版)

C# 工业常用的控件库

C# 轻松搞定工业上位机程序开机自启

C# 工业视觉开发选择 Halcon 还是 OpenCV?

C# 上位机开发怎么学?给自动化工程师的建议

.NET 桌面应用 (WPF/WinForm) 高效自动更新解决方案

一行代码快速开发 AntdUI 风格的 WinForm 通用后台框架

WinForm + SQL Server + Modbus 实现仓库温控上位机系统开发

WinForm 开发的多功能工具:串口通信、加密解密、图像转换等功能

.NET 开源免费、功能强大的图表库 ScottPlot(WinForm/WPF 通用)

C#+ OpenCvSharp 工业视觉常用图像处理示例集(开箱即用,附源码)


觉得有收获?不妨分享让更多人受益

关注「DotNet技术匠」,共同提升技术实力


收藏
点赞
分享
在看

【声明】内容源于网络
0
0
DotNet技术匠
「DotNet技术匠」聚焦.NET核心,分享深度干货、实战技巧、最新资讯、优质资源,助你领跑技术赛道,赋能开发者成长。
内容 1715
粉丝 0
DotNet技术匠 「DotNet技术匠」聚焦.NET核心,分享深度干货、实战技巧、最新资讯、优质资源,助你领跑技术赛道,赋能开发者成长。
总阅读39
粉丝0
内容1.7k