C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能
前言
上一章我們已經(jīng)實現(xiàn)了任意控件統(tǒng)一的拖動調(diào)整功能,能夠方便的給任意控件設(shè)置拖動調(diào)整大小。開發(fā)過程中發(fā)現(xiàn)還是有些功能可以繼續(xù)拓展的,比如cs代碼觸發(fā)拖動、自定義模板、交叉拖動、限制拖動范圍等功能。有功能實現(xiàn)起來不算太容易,卻很有實用價值。
一、添加的功能
在第四章基礎(chǔ)上添加了如下功能。
1、任意控件DragResize
我們知道wpf的Window有DragMove功能,在鼠標左鍵按下事件中調(diào)用此方法就能實現(xiàn)拖動功能很方便。對于調(diào)整大小也可以實現(xiàn)類似的DragResize功能, 實際效果和點擊畫板拖出一個形狀差不多。
代碼示例如下:
/// <summary> /// 手動觸發(fā)拖動改變大小,與Window.DragMove類似,只能在鼠標左鍵按下時調(diào)用。 /// 實際效果和點擊畫板拖出一個形狀差不多。 /// 此方法為拓展方法,F(xiàn)rameworkElement的子類控件(即有寬高屬性的控件)都可以調(diào)用此方法。 /// </summary> /// <param name="elememt"></param> /// <returns>返回Task,await等待拖動完成</returns> /// <exception cref="InvalidOperationException"></exception> public static async Task DragResize(this FrameworkElement elememt) { if (Mouse.LeftButton != MouseButtonState.Pressed) { throw new InvalidOperationException("Left button down to call this method"); } if (elememt.Parent == null && elememt is not Window) { throw new InvalidOperationException("Element should be on the visual tree"); } //生成Resizeable對象,第四章完整代碼中。 //獲取右下角Thumb //手動觸發(fā)Thumb拖動事件 //等待拖動完成 }
2、邊界限制
添加一個IsResizeInBounds附加屬性,表示拖動范圍是否在父控件內(nèi)。
代碼示例如下:
public static bool GetIsResizeInBounds(DependencyObject obj) { return (bool)obj.GetValue(IsResizeInBoundsProperty); } public static void SetIsResizeInBounds(DependencyObject obj, bool value) { obj.SetValue(IsResizeInBoundsProperty, value); } /// <summary> /// 是否在父控件范圍內(nèi)拖動 /// </summary> public static readonly DependencyProperty IsResizeInBoundsProperty = DependencyProperty.RegisterAttached("IsResizeInBounds", typeof(bool), typeof(Resize), new PropertyMetadata(false));
第四章的拖動邏輯中添加相應的限制功能,本質(zhì)上就是判斷如果超出邊界則控件剛好依附在邊界上,代碼如下:
var dx = left - margin.Left; var dy = top - margin.Top; if (GetIsResizeInBounds(c)) { var pos = c.GetPosition(); var parent = _resizeTarget.Parent as FrameworkElement; Size size; if (parent == null) { size.Width = SystemParameters.PrimaryScreenWidth; size.Height = SystemParameters.PrimaryScreenHeight; } else { size.Width = parent.ActualWidth; size.Height = parent.ActualHeight; } ??????? if (pos.X + dx < 0) { left = -pos.X + margin.Left; width = pos.X + c.ActualWidth; } else if (pos.X + dx + width > size.Width) { width = size.Width - pos.X; right = margin.Right + c.ActualWidth - width; } if (pos.Y + dy < 0) { top = -pos.Y + margin.Top; height = pos.Y + c.ActualHeight; } else if (pos.Y + dy + height > size.Height) { height = size.Height - pos.Y; bottom = margin.Bottom + c.ActualHeight - height; } }
3、交叉拖動
交叉拖動是曾經(jīng)用gdi畫圖時會出現(xiàn)的一種情況,gdi繪制的寬高可以為負數(shù),所以可以直接穿過起點反向拖動也能繪制出圖形。在wpf中的控件是不支持寬高負數(shù)的,所以我們需要用其他方式實現(xiàn)。
下列步驟以橫向為例:
(1)判斷控件邊界
if (width < 0)
(2)固定到控件邊界
SetTargetMargin為前3章的集合,根據(jù)不同控件類型比如Window是設(shè)置Left、Top、Grid則設(shè)置Margin等。minWidth是控件的MinWidth屬性。margin參考第四張完整代碼。
if (thumb.HorizontalAlignment == HorizontalAlignment.Left) //左拖動點 { SetTargetMargin(new Thickness(margin.Left + c.Width - minWidth, margin.Top, margin.Right - c.Width + minWidth, margin.Bottom)); } else //右拖動點 { SetTargetMargin(new Thickness(margin.Left - c.Width + minWidth, margin.Top, margin.Right + c.Width - minWidth, margin.Bottom)); }
(3)事件轉(zhuǎn)移
//當前拖動點觸發(fā)鼠標彈起事件 MouseButtonEventArgs upEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left) { RoutedEvent = UIElement.MouseLeftButtonUpEvent }; thumb.RaiseEvent(upEvent); //反向拖動點觸發(fā)鼠標按下事件 MouseButtonEventArgs downEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left) { RoutedEvent = UIElement.MouseLeftButtonDownEvent }; t.RaiseEvent(downEvent);
4、拖動點模板
添加附加屬性ThumbsTemplate
public static ControlTemplate GetThumbsTemplate(DependencyObject obj) { return (ControlTemplate)obj.GetValue(ThumbsTemplateProperty); } public static void SetThumbsTemplate(DependencyObject obj, ControlTemplate value) { obj.SetValue(ThumbsTemplateProperty, value); } /// <summary> /// 拖動點的模板 /// </summary> public static readonly DependencyProperty ThumbsTemplateProperty = DependencyProperty.RegisterAttached("ThumbsTemplate", typeof(ControlTemplate), typeof(Resize), new PropertyMetadata(null));
生成拖動點時會應用模板
var thumbsTemplate = GetThumbsTemplate(_resizeTarget); thumb.Template = thumbsTemplate;
5、拖動點容器模板
拖動點的容器模板,主要用于設(shè)置margin調(diào)整拖動點的整體位置,添加附加屬性ThumbsPanel。
public static ItemsPanelTemplate GetThumbsPanel(DependencyObject obj) { return (ItemsPanelTemplate)obj.GetValue(ThumbsPanelProperty); } public static void SetThumbsPanel(DependencyObject obj, ItemsPanelTemplate value) { obj.SetValue(ThumbsPanelProperty, value); } /// <summary> /// 拖動點的容器,主要用于設(shè)置margin /// </summary> public static readonly DependencyProperty ThumbsPanelProperty = DependencyProperty.RegisterAttached("ThumbsPanel", typeof(ItemsPanelTemplate), typeof(Resize), new PropertyMetadata(null));
生成拖動點布局時會應用模板
var itemsPanel = GetThumbsPanel(_resizeTarget); _defalutPanel.ItemsPanel = itemsPanel;
6、整體模板
拖動點模板和拖動點布局模板已經(jīng)很大程度靈活了使用,如果需要更高的定制性,直接使用整體模板,整體模板賦值后拖動點模板和拖動點布局模板會失效。此功能與第四章的ResizeTemplate相同但名稱改為Template?;疽?guī)則是第一級控件為容器、第二級控件為Thumb類型自動識別為拖動點,拖動方向由HorizontalAlignment和VerticalAlignment決定。
7、窗口平滑拖動
之所有要對窗口拖動平滑處理是因為,自定義的調(diào)整大小只能設(shè)置Window的Left、Top、Width、Height,當窗口進行左或上拖動時右或下會出現(xiàn)殘影,這種情況通過SetWindowPos和MoveWindow也無法改善。在不使用窗口自帶的拖動功能的情況下,目前筆者研究出的方法就是使用透明窗口全屏,控件模擬窗口進行拖動。當然這種實現(xiàn)的限制就是一定要透明窗口,
AllowTransparency為true或者WindowChrome的GlassFrameThickness為-1。
因為這種實現(xiàn)還不是很完美對裝飾器不兼容,所以提供IsWindowDragSmooth屬性,可以打開和關(guān)閉功能。
public static bool GetIsWindowDragSmooth(DependencyObject obj) { return (bool)obj.GetValue(IsWindowDragSmoothProperty); } ???????public static void SetIsWindowDragSmooth(DependencyObject obj, bool value) { obj.SetValue(IsWindowDragSmoothProperty, value); } /// <summary> /// 拖拽窗口調(diào)整大小是否平滑處理,作用是避免拖拽窗口左上時右下閃爍。 /// 此屬性只對窗口有效 /// 此屬性為true時需要透明窗口才能生效,即AllowTransparency為true或者WindowChrome的GlassFrameThickness為-1。 /// 當前版本不兼容有裝飾器的窗口,拖動中裝飾器可能會顯示在窗口外面。 /// </summary> // Using a DependencyProperty as the backing store for IsWindowDragSmooth. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsWindowDragSmoothProperty = DependencyProperty.RegisterAttached("IsWindowDragSmooth", typeof(bool), typeof(Resize), new PropertyMetadata(false));
8、拖動事件
提供3個拖動事件,拖動開始、拖動變化、拖動結(jié)束。
代碼示例如下:
/// <summary> /// 拖動開始事件 /// </summary> public static readonly RoutedEvent DragResizeStartedEvent = EventManager.RegisterRoutedEvent("DragResizeStarted", RoutingStrategy.Direct, typeof(EventHandler<DragResizeStartedEventArgs>), typeof(Resize)); /// <summary> /// 拖動變化事件 /// </summary> public static readonly RoutedEvent DragResizeDeltaEvent = EventManager.RegisterRoutedEvent("DragResizeDelta", RoutingStrategy.Direct, typeof(EventHandler<DragResizeDeltaEventArgs>), typeof(Resize)); /// <summary> /// 拖動結(jié)束事件 /// </summary> public static readonly RoutedEvent DragResizeCompletedEvent = EventManager.RegisterRoutedEvent("DragResizeCompleted", RoutingStrategy.Direct, typeof(EventHandler<DragResizeCompletedEventArgs>), typeof(Resize));
9、其他功能
(1)適應MinWidth、MinHeight
在第四章完整帶的基礎(chǔ)上將邊界判斷修改為控件的MinWidth、MinHeight即可。
橫向
if (width >= minWidth/*原本是0*/) { //略 }
縱向與橫向邏輯一致,修改對應變量即可,略
(2)適應MaxWidth、MaxHeight
超過了最大值需要進行修正示例如下
橫向:
if (width > c.MaxWidth) { if (thumb.HorizontalAlignment == HorizontalAlignment.Left) { left += width - c.MaxWidth; right = margin.Right; } else { left = margin.Left; right += width - c.MaxWidth; } width = c.MaxWidth; }
縱向與橫向邏輯一致,修改對應變量即可,略。
(3)適配任意dpi
所有改變坐標以及大小的代碼已經(jīng)適配了任意dpi。
主要注意的就是PointToScreen得到的坐標需要dpi轉(zhuǎn)換。
下列是獲取dpi的方法。
static Point GetDpiFromVisual(Visual visual) { var source = PresentationSource.FromVisual(visual); var dpiX = 96.0; var dpiY = 96.0; if (source?.CompositionTarget != null) { dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11; dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22; } return new Point(dpiX, dpiY); }
三、使用示例
0、基礎(chǔ)功能
這個是與第四章一致的基礎(chǔ)功能。
(1)、引用命名空間
Window 的其他屬性略
<Window xmlns:ac="clr-namespace:AC"/>
(2)、使用附加屬性
需要某個控件可以拖動調(diào)整大小則
<Grid ac:Resize.IsResizeable="True" />
(3)、窗口注意事項
當Window需要使用此功能時
<Window ac:Resize.IsResizeable="True" />
Window的拖動點會放在子控件的裝飾層,需要注意以幾點:
①Window必須有子控件,子控件有裝飾層(大部分控件都有裝飾層比如Grid、Border、Button等)。
②子控件不可限定大小需要,跟隨窗口大小變化。
③此功能與Window自帶的調(diào)整大小區(qū)別是,此功能可以用于無邊框窗口以及自定義拖動點。
1、DragResize
DragResize需要在鼠標左鍵按下事件中使用,對已存在的控件或者動態(tài)生成控件使用。此方法不需要
ac:Resize.IsResizeable="True"也可以使用。
xaml
<Window x:Class="WpfResize.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:WpfResize" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="SeaGreen" MouseLeftButtonDown="Window_MouseLeftButtonDown"/> </Window>
因為是拓展方法,所以獲取到控件對象直接調(diào)用DragResize即可。
cs
using AC; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; ???????namespace WpfResize { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //生成控件 var border = new Border(); border.Background = Brushes.Azure; border.Width = 0; border.Height = 0; //加入到容器 grid.Children.Add(border); //拖出控件 await border.DragResize(); //如果寬高為0則移除 if (border.Width == 0|| border.Height == 0) { grid.Children.Remove(border); } } } }
效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
2、邊界限制
設(shè)置ac:Resize.IsResizeInBounds="True"即可。邊界限制的范圍是父控件。
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="SeaGreen"> <Border BorderThickness="1" BorderBrush="White" Margin="40"> <StackPanel> <Border ac:Resize.IsResizeable="True" ac:Resize.IsResizeInBounds="False" Background="White" Height="100" Width="200" CornerRadius="10" > <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="不限制邊界"></TextBlock> </Border> <Border ac:Resize.IsResizeable="True" ac:Resize.IsResizeInBounds="True" Margin="0,20,0,0" Background="White" Height="100" Width="200" CornerRadius="10" > <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="限制邊界"></TextBlock> </Border> </StackPanel> </Border> </Grid> </Window>
效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
3、交叉拖動
通過附加屬性ac:Resize.IsAllowsCrossover設(shè)置是否交叉拖動,默認為true。
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="SeaGreen"> <StackPanel> <Border Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="White" Height="100" Width="200" CornerRadius="10" > <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="不允許交叉拖動"></TextBlock> </Border> <Border ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="True" Margin="0,20,0,0" Background="White" Height="100" Width="200" CornerRadius="10" > <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="允許交叉拖動"></TextBlock> </Border> </StackPanel> </Grid> </Window>
效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
4、拖動點布局模板
通過ac:Resize.ThumbsTemplate設(shè)置拖動點模板
(1)自定義圓點
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="SeaGreen " Height="100" Width="200" > <ac:Resize.ThumbsTemplate> <ControlTemplate > <Border BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Background="White" Width="16" Height="16"/> </ControlTemplate> </ac:Resize.ThumbsTemplate> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義拖動點模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
(2)4個頂點
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="SeaGreen " Height="100" Width="200" > <ac:Resize.ThumbsTemplate> <ControlTemplate > <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Background="White" Width="16" Height="16"/> <!--通過觸發(fā)器隱藏4條邊上的點--> <ControlTemplate.Triggers> <!--左右兩條邊上的點--> <Trigger Property="HorizontalAlignment" Value="Stretch"> <Setter TargetName="brd" Property="Visibility" Value="Collapsed" ></Setter> </Trigger> <!--上下兩條邊上的點--> <Trigger Property="VerticalAlignment" Value="Stretch"> <Setter TargetName="brd" Property="Visibility" Value="Collapsed" ></Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </ac:Resize.ThumbsTemplate> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義拖動點模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
(3)單獨定制每個點
通過MultiTrigger觸發(fā)器來區(qū)分每個點。
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="SeaGreen" Height="100" Width="200" > <ac:Resize.ThumbsTemplate> <ControlTemplate > <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Background="White" Width="16" Height="16"/> <ControlTemplate.Triggers> <!--左上--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Left" ></Condition> <Condition Property="VerticalAlignment" Value="Top" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Aqua"></Setter> </MultiTrigger> <!--右上--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Right" ></Condition> <Condition Property="VerticalAlignment" Value="Top" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="DarkGoldenrod"></Setter> </MultiTrigger> <!--右下--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Right" ></Condition> <Condition Property="VerticalAlignment" Value="Bottom" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="DeepPink"></Setter> </MultiTrigger> <!--左下--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Left" ></Condition> <Condition Property="VerticalAlignment" Value="Bottom" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Red"></Setter> </MultiTrigger> <!--上--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Stretch" ></Condition> <Condition Property="VerticalAlignment" Value="Top" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Gold"></Setter> </MultiTrigger> <!--下--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Stretch" ></Condition> <Condition Property="VerticalAlignment" Value="Bottom" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Indigo"></Setter> </MultiTrigger> <!--左--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Left" ></Condition> <Condition Property="VerticalAlignment" Value="Stretch" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Blue"></Setter> </MultiTrigger> <!--右--> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="HorizontalAlignment" Value="Right" ></Condition> <Condition Property="VerticalAlignment" Value="Stretch" ></Condition> </MultiTrigger.Conditions> <Setter TargetName="brd" Property="BorderBrush" Value="Green"></Setter> </MultiTrigger> </ControlTemplate.Triggers> </ControlTemplate> </ac:Resize.ThumbsTemplate> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義拖動點模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
5、拖動點容器模板
通過ac:Resize.ThumbsPanel設(shè)置拖動點容器模板,主要作用是設(shè)置margin,方便調(diào)整拖動點的偏移。
默認的容器有Margin="-3"的偏移。
(1)無Margin
此示例是為了說明無Margin的情況。
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="SeaGreen " Height="100" Width="200" > <ac:Resize.ThumbsTemplate> <ControlTemplate > <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Background="White" Width="16" Height="16"/> </ControlTemplate> </ac:Resize.ThumbsTemplate> <ac:Resize.ThumbsPanel> <ItemsPanelTemplate> <Grid></Grid> </ItemsPanelTemplate> </ac:Resize.ThumbsPanel> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義拖點容器模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
(2)設(shè)置Margin
Margin設(shè)置為拖動點的一半大小就剛好在邊線中間。
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" ac:Resize.IsAllowsCrossover="False" Background="SeaGreen " Height="100" Width="200" > <ac:Resize.ThumbsTemplate> <ControlTemplate > <Border x:Name="brd" BorderBrush="Gray" BorderThickness="2" CornerRadius="8" Background="White" Width="16" Height="16"/> </ControlTemplate> </ac:Resize.ThumbsTemplate> <ac:Resize.ThumbsPanel> <ItemsPanelTemplate> <Grid Margin="-8"></Grid> </ItemsPanelTemplate> </ac:Resize.ThumbsPanel> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義拖點容器模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
6、整體模板
設(shè)置整體模板Template后會覆蓋拖動點模板和拖動點布局模板。規(guī)則是第一級控件為容器、第二級控件為Thumb類型自動識別為拖動點,拖動方向由HorizontalAlignment和VerticalAlignment決定, 即可以有任意個拖動點Thumb,也可以放任意其他控件。
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" > <Grid x:Name="grid" Background="White"> <Grid Margin="0,20,0,0" ac:Resize.IsResizeable="True" Background="SeaGreen " Height="100" Width="200" > <ac:Resize.Template> <ControlTemplate > <Grid Margin="-4"> <Grid.Resources> <Style TargetType="Thumb"> <Setter Property="Width" Value="8"></Setter> <Setter Property="Height" Value="8"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Border Background="Aqua"></Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Grid.Resources> <Border BorderBrush="Aqua" BorderThickness="2" Margin="4"></Border> <!--左--> <Thumb HorizontalAlignment="Left" Cursor="SizeWE"/> <!--上--> <Thumb VerticalAlignment="Top" Cursor="SizeNS"/> <!--右--> <Thumb HorizontalAlignment="Right" Cursor="SizeWE"/> <!--下--> <Thumb VerticalAlignment="Bottom" Cursor="SizeNS"/> <!--左上--> <Thumb HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeNWSE"/> <!--右上--> <Thumb HorizontalAlignment="Right" VerticalAlignment="Top" Cursor="SizeNESW"/> <!--右下--> <Thumb HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE"/> <!--左下--> <Thumb HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeNESW"/> </Grid> </ControlTemplate> </ac:Resize.Template> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" Text="自定義整體模板"></TextBlock> </Grid> </Grid> </Window>
效果預覽
7、窗口平滑拖動
窗口為透明窗口(AllowTransparency為true或者WindowChrome的GlassFrameThickness為-1),附加屬性 ac:Resize.IsWindowDragSmooth設(shè)置為true即可以實現(xiàn)平滑拖動。
注:當前版本和裝飾器不兼容,拖動時裝飾器可能顯示在窗口外面,謹慎使用此屬性
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" WindowStyle="None" ResizeMode="NoResize" AllowsTransparency="True" ac:Resize.IsResizeable="True" ac:Resize.IsWindowDragSmooth="True" > <Grid Background="SeaGreen "/> </Window>
作為對比先展示非平滑拖動
注:qq錄制鼠標出現(xiàn)了偏移
設(shè)置平滑拖動效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
8、拖動事件
3個事件,拖動開始ac:Resize.DragResizeStarted、拖動變化ac:Resize.DragResizeDelta、拖動結(jié)束ac:Resize.DragResizeCompleted
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" > <Grid Background="SeaGreen "> <Border Background="Aqua" Width="200" Height="200" ac:Resize.IsResizeable="True" ac:Resize.DragResizeStarted="Border_DragResizeStarted" ac:Resize.DragResizeCompleted="Border_DragResizeCompleted" ac:Resize.DragResizeDelta="Border_DragResizeDelta"></Border> </Grid> </Window>
cs
using AC; using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace WpfResize { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Border_DragResizeStarted(object sender, DragResizeStartedEventArgs e) { Console.WriteLine("開始拖動"); } private void Border_DragResizeCompleted(object sender, DragResizeCompletedEventArgs e) { Console.WriteLine("結(jié)束拖動"); } ??????? private void Border_DragResizeDelta(object sender, DragResizeDeltaEventArgs e) { Console.WriteLine("橫向變化:"+e.HorizontalChange+ " 縱向變化:"+e.VerticalChange+ " 寬變化:" + e.WidthChange + " 高變化:" + e.HeightChange); } } }
效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
9、其他功能
(1)適應MinWidth、MinHeight
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" > <Grid Background="SeaGreen "> <Border Background="Aqua" MinWidth="100" MinHeight="100" Width="200" Height="200" ac:Resize.IsResizeable="True" ></Border> </Grid> </Window>
效果預覽
注:qq錄制鼠標出現(xiàn)了偏移
(2)適應MaxWidth、MaxHeight
xaml
<Window x:Class="WpfResize.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:WpfResize" xmlns:ac="clr-namespace:AC" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" > <Grid Background="SeaGreen "> <Border Background="Aqua" MaxWidth="200" MaxHeight="200" Width="100" Height="100" ac:Resize.IsResizeable="True" ></Border> </Grid> </Window>
效果預覽
總結(jié)
拓展后的功能更加全面以及兼容性更強了,比如DragRezie就可以用于畫板,邊界限制也是比較實用的功能,拖動點模板簡化了自定義的難度,拖動事件可以用于實現(xiàn)撤銷重做功能,窗口平滑拖動優(yōu)化了使用體驗。但是還是有些功能不夠完,需要后期繼續(xù)優(yōu)化??偟膩碚f,本文實現(xiàn)的拖動調(diào)整大小模塊已經(jīng)變得更加方便實用,后期還會繼續(xù)完善優(yōu)化。
以上就是C# wpf實現(xiàn)任意控件更多調(diào)整大小功能的詳細內(nèi)容,更多關(guān)于C# wpf控件調(diào)整的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#使用WebClient實現(xiàn)文件上傳的操作步驟
這篇文章主要介紹了C#使用WebClient實現(xiàn)文件上傳的操作步驟,文中通過代碼示例給大家介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-11-11