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]