基于WPF實(shí)現(xiàn)3D導(dǎo)航欄控件
WPF實(shí)現(xiàn)3D導(dǎo)航
框架支持.NET4 至 .NET8;
Visual Studio 2022;
AnimationNavigationBar3D 帶有 3D 效果的導(dǎo)航欄控件的樣式。包含多個(gè) AnimationNavigationBar3DItem ,通過(guò) UniformGrid 進(jìn)行排列,超出顯示區(qū)域的項(xiàng)可以滾動(dòng)查看。
AnimationNavigationBar3DItem 繼承 ListBboxItem 是 3D 導(dǎo)航欄中的每個(gè)項(xiàng)。使用 Viewport3D 來(lái)創(chuàng)建一個(gè)具有 3D 效果的容器,當(dāng)鼠標(biāo)移入或移出時(shí),旋轉(zhuǎn)動(dòng)畫(huà)來(lái)改變項(xiàng)的外觀。它包含一個(gè)正面 Background 和一個(gè)背面 ContentBack ,可以顯示不同的內(nèi)容。使用可以根據(jù)需要自定義內(nèi)容,如果在每個(gè)項(xiàng)中只設(shè)置了正面內(nèi)容而沒(méi)有設(shè)置背面內(nèi)容,那么背面會(huì)自動(dòng)克隆 GetXmlReader 并顯示與正面相同的內(nèi)容。
GetXmlReader 用于通過(guò)將 UIElement 對(duì)象轉(zhuǎn)換為 XML 字符串,再將其轉(zhuǎn)換回 UIElement 對(duì)象,實(shí)現(xiàn)對(duì) UIElement 對(duì)象的克隆。
實(shí)現(xiàn)代碼
1)新增 AnimationNavigationBar3D.cs 代碼如下:
public class AnimationNavigationBar3D : 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()
{
return new AnimationNavigationBar3DItem();
}
}
2)新增 AnimationNavigationBar3DItem.cs 代碼如下:
public class AnimationNavigationBar3DItem : ListBoxItem
{
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register("Fill", typeof(Brush), typeof(AnimationNavigationBar3DItem),
new PropertyMetadata(null));
public static readonly 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>
public object 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;
}
}
}
return null;
}
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>效果圖

以上就是基于WPF實(shí)現(xiàn)3D導(dǎo)航欄控件的詳細(xì)內(nèi)容,更多關(guān)于WPF導(dǎo)航的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Unity的Console的控制類LogEntries深入解析與實(shí)用案例
這篇文章主要為大家介紹了Unity的Console的控制類LogEntries深入解析與實(shí)用案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
基于C#實(shí)現(xiàn)PDF轉(zhuǎn)HTML并自定義轉(zhuǎn)換選項(xiàng)
在數(shù)字化辦公場(chǎng)景中,PDF與HTML的互操作需求日益增長(zhǎng),如何在 C# 生態(tài)中實(shí)現(xiàn)PDF 轉(zhuǎn) HTML 的高保真轉(zhuǎn)換是開(kāi)始過(guò)程中常見(jiàn)的問(wèn)題,下面我們就來(lái)看看具體實(shí)現(xiàn)方法吧2025-09-09
C#調(diào)用SQL語(yǔ)句時(shí)乘號(hào)的用法
這篇文章主要介紹了C#調(diào)用SQL語(yǔ)句時(shí)乘號(hào)的用法,可避免因符號(hào)引起的程序錯(cuò)誤,是C#程序設(shè)計(jì)人員有必要掌握的,需要的朋友可以參考下2014-08-08
implicit關(guān)鍵字做自定義類型隱式轉(zhuǎn)換的方法
implicit 關(guān)鍵字用于聲明隱式的用戶定義類型轉(zhuǎn)換運(yùn)算符。如果轉(zhuǎn)換過(guò)程可以確保不會(huì)造成數(shù)據(jù)丟失,則可使用該關(guān)鍵字在用戶定義類型和其他類型之間進(jìn)行隱式轉(zhuǎn)換,這篇文章就給大家詳細(xì)介紹implicit關(guān)鍵字做自定義類型隱式轉(zhuǎn)換的方法,需要的朋友可以參考下2015-08-08
采用C#代碼動(dòng)態(tài)設(shè)置文件權(quán)限
在開(kāi)發(fā)中,我們經(jīng)常會(huì)使用IO操作,例如創(chuàng)建,刪除文件等操作。在項(xiàng)目中這樣的需求也較多,我們也會(huì)經(jīng)常對(duì)這些操作進(jìn)行編碼,但是對(duì)文件的權(quán)限進(jìn)行設(shè)置,這樣的操作可能會(huì)手動(dòng)操作,本文介紹一種采用代碼動(dòng)態(tài)對(duì)文件設(shè)置權(quán)限的操作。2016-12-12
WinForm實(shí)現(xiàn)鼠標(biāo)拖動(dòng)控件跟隨效果
這篇文章主要為大家詳細(xì)介紹了WinForm實(shí)現(xiàn)鼠標(biāo)拖動(dòng)控件跟隨效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03

