Ton*_*ile 6 c# wpf xaml draggable
我的WPF应用程序有一个UserControl应该看起来和行为像弹出窗口,但它不是一个窗口.控件不会从Window类中下降的原因是因为它包含第三方虚拟屏幕键盘,并且该控件必须与TextBox它在单击其按钮时将输入字符发送到的控件位于同一窗口中.如果键盘控件不在同一窗口中,则甚至看不到TextBox控件.
拖动对话框时,我遇到的问题是表现糟糕.它足够慢,鼠标离开拖动区域,它停止跟随鼠标.我需要一个更好的方法.
以下是控件的xaml摘录:
<Grid Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Background="{DynamicResource PopupBackground}"
BorderBrush="{DynamicResource PopupBorder}"
BorderThickness="5,5,5,0"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
MouseMove="Grid_MouseMove">
. . .
</Border>
</Grid>
Run Code Online (Sandbox Code Playgroud)
这是鼠标事件处理程序:
private void Grid_MouseLeftButtonDown( object sender, MouseButtonEventArgs e ) {
Canvas canvas = Parent as Canvas;
if ( canvas == null ) {
throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
}
DraggingControl = true;
CurrentMousePosition = e.GetPosition( canvas );
e.Handled = true;
}
private void Grid_MouseLeftButtonUp( object sender, MouseButtonEventArgs e ) {
Canvas canvas = Parent as Canvas;
if ( canvas == null ) {
throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
}
if ( DraggingControl ) {
Point mousePosition = e.GetPosition( canvas );
// Correct the mouse coordinates in case they go off the edges of the control
if ( mousePosition.X < 0.0 ) mousePosition.X = 0.0; else if ( mousePosition.X > canvas.ActualWidth ) mousePosition.X = canvas.ActualWidth;
if ( mousePosition.Y < 0.0 ) mousePosition.Y = 0.0; else if ( mousePosition.Y > canvas.ActualHeight ) mousePosition.Y = canvas.ActualHeight;
// Compute the new Left & Top coordinates of the control
Canvas.SetLeft( this, Left += mousePosition.X - CurrentMousePosition.X );
Canvas.SetTop( this, Top += mousePosition.Y - CurrentMousePosition.Y );
}
e.Handled = true;
}
private void Grid_MouseMove( object sender, MouseEventArgs e ) {
Canvas canvas = Parent as Canvas;
if ( canvas == null ) {
// It is not. Throw an exception
throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
}
if ( DraggingControl && e.LeftButton == MouseButtonState.Pressed ) {
Point mousePosition = e.GetPosition( canvas );
// Correct the mouse coordinates in case they go off the edges of the control
if ( mousePosition.X < 0.0 ) mousePosition.X = 0.0; else if ( mousePosition.X > canvas.ActualWidth ) mousePosition.X = canvas.ActualWidth;
if ( mousePosition.Y < 0.0 ) mousePosition.Y = 0.0; else if ( mousePosition.Y > canvas.ActualHeight ) mousePosition.Y = canvas.ActualHeight;
// Compute the new Left & Top coordinates of the control
Canvas.SetLeft( this, Left += mousePosition.X - CurrentMousePosition.X );
Canvas.SetTop ( this, Top += mousePosition.Y - CurrentMousePosition.Y );
CurrentMousePosition = mousePosition;
}
e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)
请注意,控件必须放在Canvas使用它的窗口中.
我不能使用DragMove它,因为它是Window类的一个方法,这个类来自UserControl.如何提高此控件拖动的性能?我是否必须使用Win32 API?
您只需使用MouseDragElementBehavior即可.
UPD
关于MouseDragElementBehavior行为的重要事项:
MouseDragElementBehavior行为不适用于处理MouseClick事件的任何控件(例如,Button,TextBox和ListBox控件).如果您需要能够拖动其中一种类型的控件,请将该控件设置为可以拖动的控件的子项(例如,边框).然后,您可以将MouseDragElementBehavior行为应用于父元素.
您还可以像这样实现自己的拖动行为:
public class DragBehavior : Behavior<UIElement>
{
private Point elementStartPosition;
private Point mouseStartPosition;
private TranslateTransform transform = new TranslateTransform();
protected override void OnAttached()
{
Window parent = Application.Current.MainWindow;
AssociatedObject.RenderTransform = transform;
AssociatedObject.MouseLeftButtonDown += (sender, e) =>
{
elementStartPosition = AssociatedObject.TranslatePoint( new Point(), parent );
mouseStartPosition = e.GetPosition(parent);
AssociatedObject.CaptureMouse();
};
AssociatedObject.MouseLeftButtonUp += (sender, e) =>
{
AssociatedObject.ReleaseMouseCapture();
};
AssociatedObject.MouseMove += (sender, e) =>
{
Vector diff = e.GetPosition( parent ) - mouseStartPosition;
if (AssociatedObject.IsMouseCaptured)
{
transform.X = diff.X;
transform.Y = diff.Y;
}
};
}
}
Run Code Online (Sandbox Code Playgroud)
根据@DmitryMartovoi 的回答中的信息,我想出了一种方法来完成这项工作。我仍然给 Dmitry 一个 +1,因为如果没有他的贡献,我将无法弄清楚这一点。
我所做的是TranslateTransform在UserControl's构造函数中创建了一个并将其分配给它的RenderTransform属性:
RenderTransform = new TranslateTransform();
Run Code Online (Sandbox Code Playgroud)
在 XAML 中,我为Border用户单击以拖动整个控件的控件命名:
<Border Background="{DynamicResource PopupBackground}"
BorderBrush="{DynamicResource PopupBorder}"
BorderThickness="5,5,5,0"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
MouseMove="Grid_MouseMove"
Name="TitleBorder">
. . .
</Border>
Run Code Online (Sandbox Code Playgroud)
最后,我修改了各种鼠标事件处理程序,如下所示:
private void Grid_MouseLeftButtonDown( object sender, MouseButtonEventArgs e ) {
CurrentMousePosition = e.GetPosition( Parent as Window );
TitleBorder.CaptureMouse();
}
private void Grid_MouseLeftButtonUp( object sender, MouseButtonEventArgs e ) {
if ( TitleBorder.IsMouseCaptured ) {
TitleBorder.ReleaseMouseCapture();
}
}
private void Grid_MouseMove( object sender, MouseEventArgs e ) {
Vector diff = e.GetPosition( Parent as Window ) - CurrentMousePosition;
if ( TitleBorder.IsMouseCaptured ) {
( RenderTransform as TranslateTransform ).X = diff.X;
( RenderTransform as TranslateTransform ).Y = diff.Y;
}
}
Run Code Online (Sandbox Code Playgroud)
这很好用。UserControl当您拖动 时,整个及其所有内容都会平滑移动Border,并与鼠标保持一致。UserControl如果您单击其表面上的任何其他位置,则整体不会移动。
再次感谢@DmitryMartovoi 提供的代码。
编辑:我正在编辑这个答案,因为上面的代码虽然有效,但并不完美。它的缺陷是当您单击标题栏区域和开始拖动之前,控件会弹回到屏幕上的原始位置。这很烦人,而且完全错误。
我想出的实际上完美无缺的方法涉及首先将控件放入Canvas. 控件的父级为 a 很重要,Canvas否则以下代码将不起作用。我也停止使用RenderTransform. 我添加了一个名为canvastype的私有属性Canvas。我Loaded在弹出控件中添加了一个事件处理程序来进行一些重要的初始化:
private void KeyboardPopup_Loaded( object sender, RoutedEventArgs e ) {
canvas = Parent as Canvas;
if ( canvas == null ) {
throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
}
}
Run Code Online (Sandbox Code Playgroud)
完成所有这些后,以下是修改后的鼠标事件处理程序:
private void TitleBorder_MouseLeftButtonDown( object sender, MouseButtonEventArgs e ) {
StartMousePosition = e.GetPosition( canvas );
TitleBorder.CaptureMouse();
}
private void TitleBorder_MouseLeftButtonUp( object sender, MouseButtonEventArgs e ) {
if ( TitleBorder.IsMouseCaptured ) {
Point mousePosition = e.GetPosition( canvas );
Canvas.SetLeft( this, Canvas.GetLeft( this ) + mousePosition.X - StartMousePosition.X );
Canvas.SetTop ( this, Canvas.GetTop ( this ) + mousePosition.Y - StartMousePosition.Y );
canvas.ReleaseMouseCapture();
}
}
private void TitleBorder_MouseMove( object sender, MouseEventArgs e ) {
if ( TitleBorder.IsMouseCaptured && e.LeftButton == MouseButtonState.Pressed ) {
Point mousePosition = e.GetPosition( canvas );
// Compute the new Left & Top coordinates of the control
Canvas.SetLeft( this, Canvas.GetLeft( this ) + mousePosition.X - StartMousePosition.X );
Canvas.SetTop ( this, Canvas.GetTop ( this ) + mousePosition.Y - StartMousePosition.Y );
StartMousePosition = mousePosition;
}
}
Run Code Online (Sandbox Code Playgroud)
当您再次单击标题栏以移动控件时,控件会停留在您放置它的位置,并且仅在您单击标题栏时才会移动。单击控件中的任何其他位置什么都不做,拖动是平滑且响应迅速的。
| 归档时间: |
|
| 查看次数: |
9456 次 |
| 最近记录: |