原文: 抛砖引玉 【镜像控件】 WPF实现毛玻璃控件不要太简单
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Vblegend_2013/article/details/83447420
源码已封装成 MirrorGrid类 可以直接在XAML里添加
根据需要可以把Grid 改为 button border等控件
注意 Target必须为当前控件下层的控件对象
加个BlurEffect就是毛玻璃效果<!--玻璃层控件-->
<local:MirrorGrid
Background="Red"
Target="{Binding ElementName=box}"
Width="150"
Height="100"
x:Name="thumb" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" MouseDown="thumb_MouseDown" MouseMove="thumb_MouseMove" MouseUp="thumb_MouseUp">
<local:MirrorGrid.Effect>
<BlurEffect Radius="20" RenderingBias="Performance"/>
</local:MirrorGrid.Effect>
</local:MirrorGrid>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfApp2
{
/// <summary>
/// 镜像格子
/// </summary>
public class MirrorGrid : Grid
{
/// <summary>
/// 目标对象
/// </summary>
public FrameworkElement Target
{
get { return (FrameworkElement)GetValue(TargetProperty); }
set { SetValue(TargetProperty, value); }
}
/// <summary>
/// 目标对象属性
/// </summary>
public static readonly DependencyProperty TargetProperty =
DependencyProperty.Register("Target", typeof(FrameworkElement), typeof(MirrorGrid),
new FrameworkPropertyMetadata(null));
/// <summary>
/// 重写基类 Margin
/// </summary>
public new Thickness Margin
{
get { return (Thickness)GetValue(MarginProperty); }
set { SetValue(MarginProperty, value); }
}
public new static readonly DependencyProperty MarginProperty = DependencyProperty.Register("Margin", typeof(Thickness), typeof(MirrorGrid), new FrameworkPropertyMetadata(new Thickness(0), new PropertyChangedCallback(OnMarginChanged)));
private static void OnMarginChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
((FrameworkElement)target).Margin = (Thickness)e.NewValue;
//强制渲染
((FrameworkElement)target).InvalidateVisual();
}
protected override void OnRender(DrawingContext dc)
{
var Rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
if (Target == null)
{
dc.DrawRectangle(this.Background, null, Rect);
}
else
{
this.DrawImage(dc, Rect);
}
}
private void DrawImage(DrawingContext dc, Rect rect)
{
VisualBrush brush = new VisualBrush(Target)
{
Stretch = Stretch.Fill,
};
var tl = this.GetElementLocation(Target);
var sl = this.GetElementLocation(this);
var lx = (sl.X - tl.X) / Target.ActualWidth;
var ly = (sl.Y - tl.Y) / Target.ActualHeight;
var pw = this.ActualWidth / Target.ActualWidth;
var ph = this.ActualHeight / Target.ActualHeight;
brush.Viewbox = new Rect(lx, ly, pw, ph);
dc.DrawRectangle(brush, null, rect);
}
/// <summary>
/// 获取控件元素在窗口的实际位置
/// </summary>
/// <param name="Control"></param>
/// <returns></returns>
public Point GetElementLocation(FrameworkElement Control)
{
Point location = new Point(0, 0);
FrameworkElement element = Control;
while (element != null)
{
var Offset = VisualTreeHelper.GetOffset(element);
location = location + Offset;
element = (FrameworkElement)VisualTreeHelper.GetParent(element);
}
return location;
}
}
}
测试源码
<Window x:Class="WpfApp2.Window1"
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:WpfApp2"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<Grid ClipToBounds="True">
<!--下层被模糊层-->
<Grid x:Name="box"
Background="AntiqueWhite"
HorizontalAlignment="Left" Height="332" VerticalAlignment="Top" Width="551">
<Grid HorizontalAlignment="Left" Height="260" Margin="0,0,0,0" VerticalAlignment="Top" Width="345">
<Grid.Background>
<ImageBrush ImageSource="123.png"/>
</Grid.Background>
</Grid>
<Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="114" Margin="345,218,0,0" Stroke="Black" VerticalAlignment="Top" Width="206"/>
</Grid>
<!--玻璃层控件-->
<local:MirrorGrid
Background="Red"
Target="{Binding ElementName=box}"
Width="150"
Height="100"
x:Name="thumb" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" MouseDown="thumb_MouseDown" MouseMove="thumb_MouseMove" MouseUp="thumb_MouseUp">
<local:MirrorGrid.Effect>
<BlurEffect Radius="20" RenderingBias="Performance"/>
</local:MirrorGrid.Effect>
</local:MirrorGrid>
<!--测试边框线-->
<Rectangle Stroke="#FF2DEC0E"
IsHitTestVisible="False"
Width="{Binding ElementName=thumb, Path=Width}"
Height="{Binding ElementName=thumb, Path=Height}"
Margin="{Binding ElementName=thumb, Path=Margin}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</Window>
后台
using System.Windows;
using System.Windows.Input;
namespace WpfApp2
{
/// <summary>
/// Window1.xaml 的交互逻辑
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private bool isDragging;
private Point clickPosition;
private void thumb_MouseDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var draggableElement = sender as UIElement;
clickPosition = e.GetPosition(this);
draggableElement.CaptureMouse();
}
private void thumb_MouseUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
var draggableElement = sender as UIElement;
draggableElement.ReleaseMouseCapture();
}
private void thumb_MouseMove(object sender, MouseEventArgs e)
{
var draggableElement = sender as UIElement;
if (isDragging && draggableElement != null)
{
Point currentPosition = e.GetPosition(this.Parent as UIElement);
Thickness s = new Thickness(thumb.Margin.Left + currentPosition.X - clickPosition.X, thumb.Margin.Top + currentPosition.Y - clickPosition.Y,0,0);
thumb.Margin = s;
clickPosition = currentPosition;
}
}
}
}