wpf实现抽屉效果,一般就一个动画显示就完事了,我这用到了,就研究了一下,用装饰器给控件添加遮罩层,然后在上面添加抽屉控件,虽然麻烦了点,也算是自己研究的成果了。
看看效果:
下面就看看代码:
首先是新建一个装饰器类,和之前用过的文章:WPF 使用装饰器给控件添加遮罩层 中用的是同样的,
public class SimpleAdorner : Adorner
{
private UIElement child;
public SimpleAdorner(UIElement adornedElement) : base(adornedElement)
{
}
public UIElement Child
{
get => child;
set
{
if (value == null)
{
RemoveVisualChild(child);
}
else
{
AddVisualChild(value);
}
child = value;
}
}
protected override int VisualChildrenCount => 1;
protected override Size ArrangeOverride(Size finalSize)
{
child?.Arrange(new Rect(finalSize));
return finalSize;
}
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)
{
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(visual);
var 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);
}
}
这样就完成了,
如果喜欢,点个赞呗~