移动 WindowStyle 为 None 的 WPF 窗口





4.00/5 (7投票s)
如何移动 WindowStyle 为 None 的 WPF 窗口。
在我之前的文章中:创建自定义窗口样式,我展示了如何使用 Style 在 WPF 中创建自定义样式,使用 WindowStyle.None 和 ResizeMode.NoResize。 这种方法让我烦恼的是,你无法移动自定义窗口,因为你没有窗口边框来拖动屏幕。
我读过一篇 文章,其中使用了非常“硬核”的方法,并使用互操作来使用 SendMessage
、ReleaseCapture
和 MouseMove
方法,但这是一种非常面向 Win32 的方法,实际上,WPF 提供了更简单的方法。
要使用户能够从窗口上的任何区域移动窗口(不一定只是标题,如果你想做一些真正不同的事情),你只需处理窗口上 UIElement 的 MouseLeftButtonDown 事件,并调用 DragMove 方法,如以下代码示例所示。
private void title_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
将其连接到样式
在可重用的 Style 中定义了外观和感觉后,我们需要一种方法将 MouseLeftButtonDown 事件连接起来,并在我们的 Window 类中处理它。 遗憾的是,这有点棘手。 如果 Style 定义在定义你的 Window 的 XAML 中,那么你可以简单地为相关 UIElement 添加事件处理程序,就像对任何其他元素一样。 但是,将你的 Style 放入你的实际 Window 中并不能给你一个非常有用的 Style。 相反,给你的 Style 中的元素一个固定的名称,例如 PART_Title
,然后获取对该元素的引用,并在你的 Window 类中连接事件。 你还跟着我吗?
以下 XAML 代码示例显示了 Window Style 中的命名部分。
<style targettype=""{x:Type" type="text/css" window="" x:key=""MessageBox"">...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border Background="{DynamicResource MessageBoxBackgroundBrush}"
BorderBrush="{DynamicResource MessageBoxBorderBrush}"
BorderThickness="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="PART_Title">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF214F18" Offset="0"/>
<GradientStop Color="#FF20361C" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<Label Style="{DynamicResource MessageBoxTitle}"
Content="{TemplateBinding Title}" />
<Button x:Name="PART_Close"
Content="{DynamicResource CloseButtonPath}"
Grid.Column="1"
Style="{DynamicResource CloseButton}"
Padding="4" />
</Grid>
<AdornerDecorator Grid.Row="1">
<ContentPresenter Content="{TemplateBinding Content}"
Margin="{TemplateBinding Margin}" />
</AdornerDecorator>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter></style>
我从前一版本的 Style 所做的就是添加一个 x:Name
属性,其值为 PART_Title
到包含 Window 标题的 Grid。
以下代码示例显示了如何在 CustomMessageBox
类中获取对该元素的引用并连接鼠标事件。
namespace CustomWindow
{
/// <summary>
/// Interaction logic for CustomMessageBox.xaml
/// </summary>
public partial class CustomMessageBox : Window
{
private MessageBoxResult _result = MessageBoxResult.None;
private Button _close;
private FrameworkElement _title;
...
private void this_Loaded(object sender, RoutedEventArgs e)
{
this._close = (Button)this.Template.FindName("PART_Close", this);
if (null != this._close)
{
if (false == this._cancel.IsVisible)
{
this._close.IsCancel = false;
}
}
this._title = (FrameworkElement)this.Template.FindName("PART_Title", this);
if (null != this._title)
{
this._title.MouseLeftButtonDown +=
new MouseButtonEventHandler(title_MouseLeftButtonDown);
}
}
private void title_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
...
}
}
摘要
因此,如果你想为自定义样式的窗口启用窗口移动,那么你需要从 MouseLeftButtonDown 事件的处理程序中调用 DragMove 方法。 在此示例中,CustomMessageBox
类提供了该事件处理。 如果你正在使用一个应用于多个窗口的 Style,那么你需要在每个类中连接鼠标事件,或者实现一个提供此功能的基类并从中继承。
和以前一样,我提供了(现在已更新的)自定义消息框类的源代码。