拋磚引玉 【映象控制元件】 WPF實現毛玻璃控制元件不要太簡單
阿新 • • 發佈:2018-11-11
原文:
拋磚引玉 【映象控制元件】 WPF實現毛玻璃控制元件不要太簡單
原始碼已封裝成 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;
}
}
}
}