wpf实现抽屉效果,一般就一个动画显示就完事了,我这用到了,就研究了一下,用装饰器给控件添加遮罩层,然后在上面添加抽屉控件,虽然麻烦了点,也算是自己研究的成果了。
看看效果:
下面就看看代码:
首先是新建一个装饰器类,和之前用过的文章:WPF 使用装饰器给控件添加遮罩层 中用的是同样的,
public class SimpleAdorner : Adorner{private UIElement child;public SimpleAdorner(UIElement adornedElement) : base(adornedElement){}//Adorner 直接继承自 FrameworkElement,//没有Content和Child属性,//自己添加一个,方便向其中添加我们的控件public UIElement Child{get => child;set{if (value == null){RemoveVisualChild(child);}else{AddVisualChild(value);}child = value;}}//重写VisualChildrenCount 表示此控件只有一个子控件protected override int VisualChildrenCount => 1;//控件计算大小的时候,我们在装饰层上添加的控件也计算一下大小protected override Size ArrangeOverride(Size finalSize){child?.Arrange(new Rect(finalSize));return finalSize;}//重写GetVisualChild,返回我们添加的控件protected override Visual GetVisualChild(int index){if (index == 0 && child != null) return child;return base.GetVisualChild(index);}}
然后新建一个类:
[TemplatePart(Name = DrawerGrid,Type =typeof(Grid))][TemplatePart(Name = CloseButton,Type =typeof(Button))]public class GDrawer : ContentControl{public Action Closed;private const string DrawerGrid = "DrawerGrid";private const string CloseButton = "CloseButton";private Grid _drawerGrid;private Button _closeButton;public override void OnApplyTemplate(){base.OnApplyTemplate();_drawerGrid = GetTemplateChild(DrawerGrid) as Grid;_closeButton = GetTemplateChild(CloseButton) as Button;_closeButton.Click += (s, e) => IsOpen = false;Loaded += OnLoaded;}private void OnLoaded(object sender, RoutedEventArgs e){IsOpen = true;}public bool IsOpen{get { return (bool)GetValue(IsOpenProperty); }set { SetValue(IsOpenProperty, value); }}public static readonly DependencyProperty IsOpenProperty =DependencyProperty.Register("IsOpen", typeof(bool), typeof(GDrawer), new PropertyMetadata(false,(s,e)=> {var drawer = s as GDrawer;if(e.NewValue is bool b && b){drawer.StartAnimationIn();}else{drawer.StartAnimationOut();}}));private async void StartAnimationIn(float seconds=0.3f){var sb = new Storyboard();var offset = _drawerGrid.ActualWidth;var animation = new ThicknessAnimation{Duration = new Duration(TimeSpan.FromSeconds(seconds)),From = new Thickness(-offset,0 , offset,0 ),To = new Thickness(0)};Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));sb.Children.Add(animation);sb.Begin(_drawerGrid);await Task.Delay((int)(seconds * 1000));}private async void StartAnimationOut(float seconds=0.3f){var sb = new Storyboard();var offset = _drawerGrid.ActualWidth;var animation = new ThicknessAnimation{Duration = new Duration(TimeSpan.FromSeconds(seconds)),From = new Thickness(0),To = new Thickness(-offset, 0, offset, 0),};Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));sb.Children.Add(animation);sb.Begin(_drawerGrid);await Task.Delay((int)(seconds * 1000));Closed?.Invoke();}}
这个就是抽屉效果的实现类了,
然后,在App.xaml里添加样式和资源 :
<Style TargetType="local:GDrawer"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="local:GDrawer"><Grid x:Name="DrawerGrid" MinWidth="300" MinHeight="100" HorizontalAlignment="Left" VerticalAlignment="Stretch"Background="White"><Button x:Name="CloseButton" Margin="10" Width="50" Height="30" HorizontalAlignment="Right" VerticalAlignment="Top">关闭</Button><ContentPresenter /></Grid></ControlTemplate></Setter.Value></Setter>
</Style><local:GDrawer x:Key="LeftDrawer"><TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="18" Foreground="Red">这是内容</TextBlock></local:GDrawer>
最后,来到MainWindow窗口,xaml代码如下:
<Window x:Class="WPFDemos.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WPFDemos"mc:Ignorable="d"x:Name="widnow"WindowStartupLocation="CenterScreen"Title="title" Height="500" Width="1000"><Grid x:Name="grid" Background="LightBlue"><!--定义装饰层--><AdornerDecorator/><Button Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center">打开</Button></Grid>
</Window>
MainWindow窗体后台代码:
public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){ShowModal(grid);}SimpleAdorner _adorner = null;public void ShowModal(Visual visual){//获取visual上面的第一个AdornerLayerAdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(visual);//创建我们定义的Adornervar drawer = FindResource("LeftDrawer") as GDrawer;drawer.Closed = () => adornerLayer.Remove(_adorner);_adorner = _adorner?? new SimpleAdorner(adornerLayer){Child = new Border(){Background = new SolidColorBrush(Color.FromArgb(150, 0, 0, 0)),Child = drawer}};adornerLayer.Add(_adorner);}}
这样就完成了,
如果喜欢,点个赞呗~