如何使屏幕上像一个窗口,用户可拖动控制 [英] How to make a user control draggable on screen like a window

查看:267
本文介绍了如何使屏幕上像一个窗口,用户可拖动控制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的WPF应用程序有一个用户控件这是应该的外观和行为像一个弹出窗口,但它不是一个窗口。该控件不从窗口类下降的原因是因为它包含了第三方虚拟屏幕键盘,且该控制已在同一个窗口在文本框控制其发送的输入字符,当你点击它的按钮。如果键盘控制是不是在同一个窗口,它甚至不能看到文本框控制。

My WPF application has a UserControl which is supposed to look and behave like a popup window, but it isn't a window. The reason the control doesn't descend from the Window class is because it contains a third-party virtual on-screen keyboard, and that control has to be in the same window as the TextBox controls that it sends input characters to when you click on its buttons. If the keyboard control is not in the same window, it can't even see the TextBox controls.

我遇到的问题是周围拖动对话框时表现糟糕透顶。这是足够慢鼠标脱落的阻力区域,它停止跟随鼠标移动。我需要一个更好的办法

The problem I'm having is performance is abysmal when dragging the dialog around. It's sufficiently slow that the mouse comes off the drag area and it stops following the mouse. I need a better way.

下面是从XAML为控制摘录:

Here's an excerpt from the xaml for the control:

<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>

下面是鼠标事件处理程序:

Here's the mouse event handlers:

    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;
    }

请注意,该控件必须放在 Canvas中在使用它的窗口。

Note that the control must be placed inside a Canvas in the window that uses it.

我不能使用 DragMove ,因为它是在窗口和这个类的方法从用户控件下降。如何改善这种控制的拖曳的表现?我必须诉诸Win32 API的?

I can't use DragMove as it's a method of the Window class and this class descends from UserControl. How do I improve the performance of this control's dragging? Do I have to resort to Win32 APIs?

推荐答案

在@ DmitryMartovoi的回答基于的信息,我想出了一个办法使这项工作。我仍然给梅德一个+1,因为我不会已经能够推测出没有他的贡献。

Based upon information in @DmitryMartovoi's answer, I have come up with a way to make this work. I'm still giving Dmitry a +1 as I wouldn't have been able to figure this out without his contribution.

我所做的就是我创建了一个 TranslateTransform 在我的用户控件的的构造函数,并分配给它的的RenderTransform 属性:

What I did was I created a TranslateTransform in my UserControl's constructor and assigned it to its RenderTransform property:

RenderTransform = new TranslateTransform();

在XAML,我命名为边框用户点击控件拖动整个控制:

In the XAML, I named the Border control that the user clicks on to drag the whole control:

<Border Background="{DynamicResource PopupBackground}"
        BorderBrush="{DynamicResource PopupBorder}"
        BorderThickness="5,5,5,0"
        MouseLeftButtonDown="Grid_MouseLeftButtonDown"
        MouseLeftButtonUp="Grid_MouseLeftButtonUp"
        MouseMove="Grid_MouseMove"
        Name="TitleBorder">

    . . .
</Border>



最后,我修改了各种鼠标事件处理程序如下:

Finally, I modified the various Mouse event handlers as follows:

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;
    }
}

本精美的作品。整个用户控件及其所有内容移动顺利,当你拖动边框,紧跟鼠标。而整个用户控件如果你点击任何地方它的表面上不动。

This works beautifully. The entire UserControl and all of its contents move smoothly when you drag the Border, keeping up with the mouse. And the entire UserControl does not move if you click anywhere else on its surface.

再次感谢@DmitryMartovoi为他提供的代码

Thanks again to @DmitryMartovoi for the code he supplied.

编辑:我编辑这个答案,因为上面的代码,而它的工作,是不完美的。它的缺点是,当你点击标题栏区域,你开始之前,拖动控制会弹回原来的位置在屏幕上。这是恼人的和完全错误的。

I am editing this answer because the above code, while it worked, wasn't perfect. Its flaw is that the control would pop back to its original location on screen when you clicked on the title bar area and before you started dragging. This was annoying and totally wrong.

我想出了实际工作完美无缺参与第一投入画布<控制的方法/ code>。该控件的父是画布或下面的代码将无法正常工作是非常重要的。我还用的RenderTransform 停止。我添加了名为画布类型画布私有财产。我添加了一个加载事件处理程序弹出控制做一些重要的初始化:

The approach I came up with that actually worked flawlessly involved first putting the control in a Canvas. It's important that the parent of the control be a Canvas or the following code won't work. I also stopped using the RenderTransform. I added a private property called canvas of type Canvas. I added a Loaded event handler to the popup control to do some important initialization:

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." );
    }    
}



有了这一切完成后,这里是修改后的鼠标事件处理程序:

With all of this done, here are the modified Mouse event handlers:

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;
    }
}



在这里你放弃了它,当你点击控件保持标题栏将它移到第二次,而且只有当你点击标题栏上移动。点击其他任何地方控制不执行任何操作,并拖动平稳,反应灵敏。

The control stays where you dropped it when you click on the title bar to move it a second time, and it only moves when you click on the title bar. Clicking anywhere else in the control does nothing, and dragging is smooth and responsive.

这篇关于如何使屏幕上像一个窗口,用户可拖动控制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆