WPF 中使用附加属性,将任意 UI 元素或控件裁剪成圆形(椭圆)
版權聲明:本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名呂毅(包含鏈接:http://blog.csdn.net/wpwalter/),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布。如有任何疑問,請與我聯系(walter.lv@qq.com)。 https://blog.csdn.net/WPwalter/article/details/80820818
不知從什么時候開始,頭像流行使用圓形了,于是各個平臺開始追逐顯示圓形裁剪圖像的技術。WPF 作為一個優秀的 UI 框架,當然有其內建的機制支持這種圓形裁剪。
不過,內建的機制僅支持畫刷,而如果被裁剪的元素支持交互,或者擁有普通畫刷無法達到的顯示效果,那么就需要本文介紹的更加通用的解決方法了。
UWP 的圓形裁剪請左轉參考:UWP 將圖片裁剪成圓形(橢圓)。
WPF 的 UIElement 提供了 Clip 依賴項屬性,可以使用一個 Geometry 來裁剪任意的 UIElement。由于 Geometry 幾乎可以表示任意形狀,這意味著我們可以才建成任意想要的樣子。
于是,我們可以利用這一點,使用 EllipseGeometry 將任意 UIElement 裁剪成圓形或者橢圓形。比如,寫成下面這樣:
<Grid><Grid.Clip><EllipseGeometry Center="120 180" RadiusX="120" RadiusY="180" /></Grid.Clip><Image Source="demo.jpg" Stretch="Fill" /><TextBlock Text="https://walterlv.github.io" Foreground="White" Margin="171,172,51,21"/> </Grid>最終可以出現如下的效果。
不過,稍微改變下窗口的大小,就會發現裁剪的范圍不對了。因為我們寫死了圓形裁剪的中心點和兩個不同方向的半徑(這里可不好說是長半軸還是短半軸啊)。
我們需要一個可以自動修改裁剪圓形的一種機制,于是,我們想到了 Binding。為了使 XAML 的代碼好看一點,我將 Binding 封裝到了一個單獨的類中處理,使用附加屬性提供 API。
我封裝好的類如下:
/// <summary> /// 提供將任意控件裁剪為圓形或橢圓的附加屬性。 /// </summary> public static class EllipseClipper {/// <summary>/// 標識 IsClipping 的附加屬性。/// </summary>public static readonly DependencyProperty IsClippingProperty = DependencyProperty.RegisterAttached("IsClipping", typeof(bool), typeof(EllipseClipper), new PropertyMetadata(false, OnIsClippingChanged));public static void SetIsClipping(DependencyObject element, bool value)=> element.SetValue(IsClippingProperty, value);public static bool GetIsClipping(DependencyObject element)=> (bool) element.GetValue(IsClippingProperty);private static void OnIsClippingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var source = (UIElement) d;if (e.NewValue is false){// 如果 IsClipping 附加屬性被設置為 false,則清除 UIElement.Clip 屬性。source.ClearValue(UIElement.ClipProperty);return;}// 如果 UIElement.Clip 屬性被用作其他用途,則拋出異常說明問題所在。var ellipse = source.Clip as EllipseGeometry;if (source.Clip != null && ellipse == null){throw new InvalidOperationException($"{typeof(EllipseClipper).FullName}.{IsClippingProperty.Name} " +$"is using {source.GetType().FullName}.{UIElement.ClipProperty.Name} " +"for clipping, dont use this property manually.");}// 使用 UIElement.Clip 屬性。ellipse = ellipse ?? new EllipseGeometry();source.Clip = ellipse;// 使用綁定來根據控件的寬高更新橢圓裁剪范圍。var xBinding = new Binding(FrameworkElement.ActualWidthProperty.Name){Source = source,Mode = BindingMode.OneWay,Converter = new HalfConverter(),};var yBinding = new Binding(FrameworkElement.ActualHeightProperty.Name){Source = source,Mode = BindingMode.OneWay,Converter = new HalfConverter(),};var xyBinding = new MultiBinding{Converter = new SizeToClipCenterConverter(),};xyBinding.Bindings.Add(xBinding);xyBinding.Bindings.Add(yBinding);BindingOperations.SetBinding(ellipse, EllipseGeometry.RadiusXProperty, xBinding);BindingOperations.SetBinding(ellipse, EllipseGeometry.RadiusYProperty, yBinding);BindingOperations.SetBinding(ellipse, EllipseGeometry.CenterProperty, xyBinding);}private sealed class SizeToClipCenterConverter : IMultiValueConverter{public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)=> new Point((double) values[0], (double) values[1]);public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)=> throw new NotSupportedException();}private sealed class HalfConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture)=> (double) value / 2;public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)=> throw new NotSupportedException();} }在 XAML 中只需要很簡單的一個屬性賦值即可達到圓形或橢圓形裁剪。
<Grid local:EllipseClipper.IsClipping="True"><Image Source="fluentdesign-app-header.jpg" Stretch="Fill" /><TextBlock Text="https://walterlv.github.io" Foreground="White" Margin="171,172,51,21"/> </Grid>而且才控件的大小改變的時候也能夠正常更新裁剪范圍。
這篇博客的核心代碼我也貼在了 StackOverflow 上:c# - WPF displaying a gif in an ellipse - Stack Overflow
總結
以上是生活随笔為你收集整理的WPF 中使用附加属性,将任意 UI 元素或控件裁剪成圆形(椭圆)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 006 CSS三种引入方式
- 下一篇: 1.2.1bat脚本命令 DIR 显示磁