1. 程式人生 > >WPF 使用鼠標拖動一個控件的實現[2018.7.15]

WPF 使用鼠標拖動一個控件的實現[2018.7.15]

ont wpf horizon edit 導致 cal 自己的 進行 sdn

原文:WPF 使用鼠標拖動一個控件的實現[2018.7.15]

Q:已經把一個Shape和一個TextBlock組合起來放到了一個Grid中,現在想要實現用鼠標拖動這個Grid到任意位置的功能,如何做?

<Grid Height="50" Width="50">
    <Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
    <TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>

A:在stackoverflow上找到解決方法。首先,為這個Grid添加三個鼠標事件

<Grid Height="50" Width="50" MouseLeftButtonDown="grid_MouseLeftButtonDown" MouseLeftButtonUp="
    grid_MouseLeftButtonUp" MouseMove="grid_MouseMove">
    <Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
    <TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>

?

在cs文件中為這三個事件添加實現:

private bool isDragging;
private Point clickPosition;

private void grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    isDragging = true;
    var draggableElement = sender as UIElement;
    clickPosition = e.GetPosition(this);
    draggableElement.CaptureMouse();
}

private void grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    isDragging = false;
    var draggableElement = sender as UIElement;
    draggableElement.ReleaseMouseCapture();
}

private void grid_MouseMove(object sender, MouseEventArgs e)
{
    var draggableElement = sender as UIElement;
    if (isDragging && draggableElement != null)
    {
        Point currentPosition = e.GetPosition(this.Parent as UIElement);
        var transform = draggableElement.RenderTransform as TranslateTransform;
        if (transform == null)
        {
            transform = new TranslateTransform();
            draggableElement.RenderTransform = transform;
        }
        transform.X = currentPosition.X - clickPosition.X;
        transform.Y = currentPosition.Y - clickPosition.Y;
     }
} 

?

? ? ? 每個控件有一個RenderTransform屬性,它接收一個對象。TranslateTransform是RenderTransform的一個子類,它的實例可以賦給控件的RenderTransform屬性,表示以當前控件為原點進行的平移操作。

? ? 【---2018.7.17添加---】?

? ? ?上面這段c#代碼有問題。當拖動控件移動後,松開鼠標,如果再次想要拖動該控件,在鼠標剛按下時控件會回到原點。

? ? ? 出現這個問題是因為在MouseLeftButtonDown事件發生後,立即發生MouseMove事件,currentPosition和clickPosition相等,導致transform的X和Y屬性都為0。從而grid的RenderTransform屬性指示將控件重新繪制在grid的起始位置。

? ? ? 對於RenderTransform屬性來說,原點是多少?應該是grid控件對象被創建時的坐標。RenderTransform指示的移動都是以這個坐標軸為參考的。

? ? ? ?解決這個問題的方法是,在grid_MouseMove()中,每次移動的時候,要加上上一次拖拽結束時控件的相對坐標。

? ? ? ?首先為這個grid添加一個名字,並使用RenderTransform屬性

<Grid Height="50" Width="50" Name="myGrid" MouseLeftButtonDown="grid_MouseLeftButtonDown" MouseLeftButtonUp="
    grid_MouseLeftButtonUp" MouseMove="grid_MouseMove">
    <Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
    <TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
    <Grid.RenderTransform>
        <TranslateTransform x:Name="tt" />
    </RenderTransform>
</Grid>

? ? 然後,將cs代碼中的clickPosition取消,換一個名字,比如叫startPosition,用來記錄該控件在任一時刻離自己的原點的相對坐標。在grid_MouseLeftButtonDown方法中,不記錄鼠標點擊的位置坐標,而是記錄鼠標被按下時這個位置離控件原點的距離,即剛剛定義的startPosition。

? ? ? 在grid_MouseMove方法中,由於grid的RenderTransform早有定義,所以不用進行是否null的判斷。之後transform變量的值,應該為當前坐標currentPosition與參考點startPosition之差。

private bool isDragging;
private Point startPosition;

private void grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    isDragging = true;
    var draggableElement = sender as UIElement;
    var clickPosition = e.GetPosition(this);

    var transform = draggableElement.RenderTranform as TranslateTransform;
    startPosition.X = clickPosition.X - transform.X;    //註意減號
    startPosition.Y = clickPosition.Y - transform.Y;

    draggableElement.CaptureMouse();
}

private void grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    isDragging = false;
    var draggableElement = sender as UIElement;
    draggableElement.ReleaseMouseCapture();
}

private void grid_MouseMove(object sender, MouseEventArgs e)
{
    var draggableElement = sender as UIElement;
    if (isDragging && draggableElement != null)
    {
        Point currentPosition = e.GetPosition(this.Parent as UIElement);
        var transform = draggableElement.RenderTransform as TranslateTransform;

        transform.X = currentPosition.X - startPosition.X;
        transform.Y = currentPosition.Y - startPosition.Y;
     }
} 

?

WPF 使用鼠標拖動一個控件的實現[2018.7.15]