WPF實(shí)現(xiàn)Drawer抽屜控件
Drawer 抽屜控件的實(shí)現(xiàn)
框架支持.NET4 至 .NET8
;
Visual Studio 2022
;
抽屜控件的邏輯實(shí)現(xiàn)
定義了一個(gè)名為 Drawer
的自定義控件,繼承自 HeaderedContentControl
,允許用戶在應(yīng)用程序中創(chuàng)建可展開(kāi)和收起的抽屜。抽屜的顯示和隱藏動(dòng)畫(huà)通過(guò) Storyboard
實(shí)現(xiàn),支持從不同方向(左
、上
、右
、下
)展開(kāi)和收起。
1.定義模板
使用 TemplatePart
特性定義了兩個(gè)模板:BorderHeaderTemplateName
和 BorderMarkTemplateName
,分別代表抽屜的頭
和蒙板
部分。
[TemplatePart(Name = BorderHeaderTemplateName, Type = typeof(Border))] [TemplatePart(Name = BorderMarkTemplateName, Type = typeof(Border))] public class Drawer : HeaderedContentControl
2.定義依賴屬性
Position
抽屜展開(kāi)的方向(左
、上
、右
、下
)。IsOpen
抽屜是否打開(kāi),狀態(tài)變化時(shí)調(diào)用OnIsOpenChanged
方法。
public static readonly DependencyProperty EdgePositionProperty = DependencyProperty.Register("Position", typeof(Position), typeof(Drawer), new PropertyMetadata(Position.Left)); public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(Drawer), new PropertyMetadata(false, OnIsOpenChanged));
3.屬性實(shí)現(xiàn)
public Position Position { get => (Position) GetValue(EdgePositionProperty); set => SetValue(EdgePositionProperty, value); } public bool IsOpen { get => (bool) GetValue(IsOpenProperty); set => SetValue(IsOpenProperty, value); }
4.狀態(tài)變化處理
OnIsOpenChanged
方法根據(jù) IsOpen
屬性的值,控制抽屜的顯示或隱藏和動(dòng)畫(huà)效果。
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var ctrl = d as Drawer; if (ctrl != null) { if (ctrl.IsOpen) { ctrl._headerBorder.Visibility = Visibility.Visible; ctrl._enterStoryboard.Begin(); } else { ctrl._exitStoryboard.Begin(); } } }
5.模板應(yīng)用
OnApplyTemplate
方法在控件模板應(yīng)用時(shí)調(diào)用,獲取模板中的 Border
部件并注冊(cè) Loaded
和 MouseDown
事件。
public override void OnApplyTemplate() { base.OnApplyTemplate(); _headerBorder = GetTemplateChild(BorderHeaderTemplateName) as Border; if (_headerBorder != null) _headerBorder.Loaded += HeaderBorder_Loaded; _markBorder = GetTemplateChild(BorderMarkTemplateName) as Border; if (_markBorder != null) _markBorder.MouseDown += MarkBorder_MouseDown; }
6.動(dòng)畫(huà)實(shí)現(xiàn)
HeaderBorder_Loaded
方法根據(jù) Position
的不同,設(shè)置不同的動(dòng)畫(huà),并根據(jù)屬性值控制動(dòng)畫(huà)的執(zhí)行。
private void HeaderBorder_Loaded(object sender, RoutedEventArgs e) { TranslateTransform translateTransform; DoubleAnimation animation, exitAnimation; switch (Position) { case Position.Left: case Position.Right: _headerWidth = _headerBorder.ActualWidth; if (Position == Position.Left) translateTransform = new TranslateTransform(-_headerWidth, 0); else translateTransform = new TranslateTransform(_headerWidth, 0); _headerBorder.RenderTransform = new TransformGroup { Children = new TransformCollection {translateTransform} }; animation = new DoubleAnimation { From = Position == Position.Left ? -_headerWidth : _headerWidth, To = 0, Duration = TimeSpan.FromMilliseconds(300) }; Storyboard.SetTarget(animation, _headerBorder); Storyboard.SetTargetProperty(animation, new PropertyPath("RenderTransform.Children[0].X")); _enterStoryboard = new Storyboard(); _enterStoryboard.Children.Add(animation); exitAnimation = new DoubleAnimation { From = 0, To = Position == Position.Left ? -_headerWidth : _headerWidth, Duration = TimeSpan.FromMilliseconds(300) }; Storyboard.SetTarget(exitAnimation, _headerBorder); Storyboard.SetTargetProperty(exitAnimation, new PropertyPath("RenderTransform.Children[0].X")); _exitStoryboard = new Storyboard(); _exitStoryboard.Completed += delegate { if (!IsOpen) _headerBorder.Visibility = Visibility.Collapsed; }; _exitStoryboard.Children.Add(exitAnimation); break; case Position.Top: case Position.Bottom: _headerHeight = _headerBorder.ActualHeight; if (Position == Position.Top) translateTransform = new TranslateTransform(0, -_headerHeight); else translateTransform = new TranslateTransform(0, _headerHeight); _headerBorder.RenderTransform = new TransformGroup { Children = new TransformCollection {translateTransform} }; animation = new DoubleAnimation { From = Position == Position.Top ? -_headerHeight : _headerHeight, To = 0, Duration = TimeSpan.FromMilliseconds(300) }; Storyboard.SetTarget(animation, _headerBorder); Storyboard.SetTargetProperty(animation, new PropertyPath("RenderTransform.Children[0].Y")); _enterStoryboard = new Storyboard(); _enterStoryboard.Children.Add(animation); exitAnimation = new DoubleAnimation { From = 0, To = Position == Position.Top ? -_headerHeight : _headerHeight, Duration = TimeSpan.FromMilliseconds(300) }; Storyboard.SetTarget(exitAnimation, _headerBorder); Storyboard.SetTargetProperty(exitAnimation, new PropertyPath("RenderTransform.Children[0].Y")); _exitStoryboard = new Storyboard(); _exitStoryboard.Completed += delegate { if (!IsOpen) _headerBorder.Visibility = Visibility.Collapsed; }; _exitStoryboard.Children.Add(exitAnimation); break; } _headerBorder.Visibility = Visibility.Collapsed; _headerBorder.Loaded -= HeaderBorder_Loaded; }
抽屜控件的樣式實(shí)現(xiàn)
Position
屬性的觸發(fā)器:根據(jù) Position
屬性的值(Top
、Right
、Bottom
),調(diào)整 PART_Header
的對(duì)齊方式。
IsOpen
屬性的觸發(fā)器:如果 IsOpen
為 False
,將 PART_Mark
的可見(jiàn)性設(shè)置為 Collapsed
,在抽屜關(guān)閉時(shí)隱藏。
<Style x:Key="WD.Drawer" BasedOn="{StaticResource WD.ControlBasicStyle}" TargetType="{x:Type controls:Drawer}"> <Setter Property="Background" Value="{DynamicResource WD.BackgroundSolidColorBrush}" /> <Setter Property="BorderBrush" Value="{DynamicResource WD.BaseSolidColorBrush}" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type controls:Drawer}"> <controls:WDBorder x:Name="Border" Margin="{TemplateBinding Margin}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{Binding Path=(helpers:ElementHelper.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}" SnapsToDevicePixels="True"> <controls:SmallPanel Clip="{Binding RelativeSource={RelativeSource AncestorType=controls:WDBorder}, Path=ContentClip}"> <Border x:Name="PART_Content"> <ContentPresenter Content="{TemplateBinding Content}" /> </Border> <Border x:Name="PART_Mark" Background="{DynamicResource WD.PrimaryTextSolidColorBrush}" Opacity=".5" /> <Border x:Name="PART_Header" HorizontalAlignment="Left" Background="{TemplateBinding Background}" Effect="{StaticResource WD.NormalShadowDepth}"> <ContentPresenter Content="{TemplateBinding Header}" /> </Border> </controls:SmallPanel> </controls:WDBorder> <ControlTemplate.Triggers> <Trigger Property="Position" Value="Top"> <Setter TargetName="PART_Header" Property="HorizontalAlignment" Value="Stretch" /> <Setter TargetName="PART_Header" Property="VerticalAlignment" Value="Top" /> </Trigger> <Trigger Property="Position" Value="Right"> <Setter TargetName="PART_Header" Property="HorizontalAlignment" Value="Right" /> <Setter TargetName="PART_Header" Property="VerticalAlignment" Value="Stretch" /> </Trigger> <Trigger Property="Position" Value="Bottom"> <Setter TargetName="PART_Header" Property="HorizontalAlignment" Value="Stretch" /> <Setter TargetName="PART_Header" Property="VerticalAlignment" Value="Bottom" /> </Trigger> <Trigger Property="IsOpen" Value="False"> <Setter TargetName="PART_Mark" Property="Visibility" Value="Collapsed" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
示例
示例引入 WPFDevelopers
的 Nuget
包
<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.DrawerExample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:WPFDevelopers.Samples.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers" d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> <controls:CodeViewer> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <wd:Drawer x:Name="MyDrawerTop" Margin="2" Position="Top"> <wd:Drawer.Header> <Grid Height="120"> <StackPanel HorizontalAlignment="Center"> <TextBlock FontSize="18" Text="Drawer" /> <Button HorizontalAlignment="Center" Content="contents..." /> </StackPanel> </Grid> </wd:Drawer.Header> <wd:Drawer.Content> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom"> <TextBlock Text="抽屜從頂部置滑出,點(diǎn)擊遮罩區(qū)關(guān)閉。" /> <Button Margin="0,10" HorizontalAlignment="Center" Click="ButtonTop_Click" Content="Open" Style="{StaticResource WD.PrimaryButton}" /> </StackPanel> </wd:Drawer.Content> </wd:Drawer> <wd:Drawer x:Name="MyDrawerBottom" Grid.Column="1" Margin="2" wd:ElementHelper.CornerRadius="3" Position="Bottom"> <wd:Drawer.Header> <Grid Height="130"> <StackPanel HorizontalAlignment="Center"> <TextBlock FontSize="18" Text="Drawer" /> <Button HorizontalAlignment="Center" wd:ElementHelper.CornerRadius="3" Content="contents..." Style="{StaticResource WD.DangerDefaultButton}" /> </StackPanel> </Grid> </wd:Drawer.Header> <wd:Drawer.Content> <StackPanel HorizontalAlignment="Center"> <TextBlock Text="抽屜從底部滑出,點(diǎn)擊遮罩區(qū)關(guān)閉。" /> <Button Margin="0,10" HorizontalAlignment="Center" wd:ElementHelper.CornerRadius="3" Click="ButtonBottom_Click" Content="Open" Style="{StaticResource WD.DangerPrimaryButton}" /> </StackPanel> </wd:Drawer.Content> </wd:Drawer> <wd:Drawer x:Name="MyDrawerLeft" Grid.Row="1" Margin="2" wd:ElementHelper.CornerRadius="3" Position="Left"> <wd:Drawer.Header> <Grid Width="140" Background="HotPink"> <StackPanel> <TextBlock HorizontalAlignment="Center" FontSize="18" Text="Drawer" /> <Button HorizontalAlignment="Center" wd:ElementHelper.CornerRadius="3" Content="contents..." Style="{StaticResource WD.SuccessDefaultButton}" /> </StackPanel> </Grid> </wd:Drawer.Header> <wd:Drawer.Content> <StackPanel HorizontalAlignment="Center"> <TextBlock Text="抽屜從左側(cè)滑出,點(diǎn)擊遮罩區(qū)關(guān)閉。" /> <Button Margin="0,10" HorizontalAlignment="Center" wd:ElementHelper.CornerRadius="3" Click="ButtonLeft_Click" Content="Open" Style="{StaticResource WD.SuccessPrimaryButton}" /> </StackPanel> </wd:Drawer.Content> </wd:Drawer> <wd:Drawer x:Name="MyDrawerRight" Grid.Row="1" Grid.Column="1" Margin="2" Position="Right"> <wd:Drawer.Header> <Grid Width="100"> <StackPanel HorizontalAlignment="Center"> <TextBlock HorizontalAlignment="Center" FontSize="18" Text="Drawer" /> <Button HorizontalAlignment="Center" Content="contents..." Style="{StaticResource WD.WarningDefaultButton}" /> </StackPanel> </Grid> </wd:Drawer.Header> <wd:Drawer.Content> <StackPanel HorizontalAlignment="Center"> <TextBlock Text="抽屜從右側(cè)滑出,點(diǎn)擊遮罩區(qū)關(guān)閉。" /> <Button Margin="0,10" HorizontalAlignment="Center" Click="ButtonRight_Click" Content="Open" Style="{StaticResource WD.WarningPrimaryButton}" /> </StackPanel> </wd:Drawer.Content> </wd:Drawer> </Grid> <controls:CodeViewer.SourceCodes> <controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/DrawerExample.xaml" CodeType="Xaml" /> <controls:SourceCodeModel CodeSource="/WPFDevelopers.SamplesCode;component/ExampleViews/DrawerExample.xaml.cs" CodeType="CSharp" /> </controls:CodeViewer.SourceCodes> </controls:CodeViewer> </UserControl>
效果圖
到此這篇關(guān)于WPF實(shí)現(xiàn)Drawer抽屜控件的文章就介紹到這了,更多相關(guān)WPF抽屜控件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
linux操作系統(tǒng)安裝MONO執(zhí)行C#程序的詳解步驟
這篇文章主要介紹了linux操作系統(tǒng)安裝MONO執(zhí)行C#程序詳解步驟,有需要的可以參考一下2013-12-12c#數(shù)據(jù)綁定之向查詢中添加參數(shù)(.Net連接外部數(shù)據(jù)庫(kù))
本實(shí)例主要練習(xí)了ADO.Net連接到外部數(shù)據(jù)庫(kù)的基礎(chǔ)上,向查詢中添加參數(shù)。使用的是ACCESS數(shù)據(jù)庫(kù)2014-04-04C# Chart折線圖使用鼠標(biāo)滾輪放大、縮小和平移曲線方式
這篇文章主要介紹了C# Chart折線圖使用鼠標(biāo)滾輪放大、縮小和平移曲線方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Windows下C#的GUI窗口程序中實(shí)現(xiàn)調(diào)用Google Map的實(shí)例
這篇文章主要介紹了Windows下C#的GUI窗口程序中實(shí)現(xiàn)調(diào)用Google Map的實(shí)例,如果只想調(diào)用瀏覽器打開(kāi)網(wǎng)頁(yè)的話可以看文章最后的方法,需要的朋友可以參考下2016-04-04C#實(shí)現(xiàn)嵌套循環(huán)的示例代碼
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)嵌套循環(huán)的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09C#實(shí)現(xiàn)Winform版計(jì)算器
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Winform版計(jì)算器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05C#實(shí)現(xiàn)Excel動(dòng)態(tài)生成PivotTable
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)Excel動(dòng)態(tài)生成PivotTable的相關(guān)方法,感興趣的小伙伴們可以參考一下2016-04-04