WPF ポップアップ コントロールをドラッグします
質問
WPF ポップアップ コントロールは優れていますが、私の意見では多少制限があります。(Windows の DragMove() メソッドのように) ポップアップが開かれたときにポップアップを「ドラッグ」する方法はありますか?
これは大きな問題なく実行できますか、それともポップアップ クラスの代替を自分で作成する必要がありますか?ありがとう
解決
Thumbを使用した簡単なソリューションです。
- XAMLおよび分離コードのサブクラスポップアップ
- 幅/高さを0に設定してThumbを追加します(これはXAMLでも実行できます)
- ポップアップでMouseDownイベントをリッスンし、Thumbで同じイベントを発生させます
- DragDeltaでポップアップを移動する
XAML:
<Popup x:Class="PopupTest.DraggablePopup" ...>
<Canvas x:Name="ContentCanvas">
</Canvas>
</Popup>
C#:
public partial class DraggablePopup : Popup
{
public DraggablePopup()
{
var thumb = new Thumb
{
Width = 0,
Height = 0,
};
ContentCanvas.Children.Add(thumb);
MouseDown += (sender, e) =>
{
thumb.RaiseEvent(e);
};
thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
}
他のヒント
PopUp用のDragMoveはありません。ちょっとした回避策ですが、これに追加できる多くの改善点があります。
<Popup x:Name="pop" IsOpen="True" Height="200" Placement="AbsolutePoint" Width="200">
<Rectangle Stretch="Fill" Fill="Red"/>
</Popup>
コードビハインドで、このmousemoveイベントを追加します
pop.MouseMove += new MouseEventHandler(pop_MouseMove);
void pop_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
pop.PlacementRectangle = new Rect(new Point(e.GetPosition(this).X,
e.GetPosition(this).Y),new Point(200,200));
}
}
これを実現するもう 1 つの方法は、ポップアップの配置を MousePoint に設定することです。これにより、ポップアップは最初はマウス カーソルの位置に表示されます。
次に、Thumb または MouseMove イベントを使用して、ポップアップの horizontaloffset およびverticaloffset を設定できます。これらのプロパティは、ユーザーがポップアップをドラッグすると、ポップアップを元の位置からずらします。
次回ポップアップを使用するときは、必ず 水平オフセットと垂直オフセットをゼロにリセットしてください。
移動が速すぎるとマウスを失う問題は解決できました
これはmsdnから取得されます:
新しいウィンドウには、ポップアップの子コンテンツが含まれます。
Popupコントロールは、その子コンテンツへの参照を論理的な子として維持します。新しいウィンドウが作成されると、ポップアップのコンテンツはウィンドウの視覚的な子になり、ポップアップの論理的な子のままになります。逆に、ポップアップはその子コンテンツの論理的な親のままです。
つまり、ポップアップの子はスタンドアロンウィンドウに表示されます。
だから次のことをしようとすると:
Popup.CaptureMouse()
は、ポップアップ自体ではなくラッパーウィンドウをキャプチャしています。代わりに、 Popup.Child.CaptureMouse()
を使用すると、実際のポップアップがキャプチャされます。
その他のすべてのイベントは、 Popup.Child
を使用して登録する必要があります。
Popup.Child.MouseMove
、 Popup.Child.LostCapture
などのように
これはテスト済みであり、完全に正常に動作します
Private Point startPoint;
private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point relative = e.GetPosition(null);
Point AbsolutePos = new Point(relative.X + this.Left, relative.Y + this.Top);
this.Top = AbsolutePos.Y - startPoint.Y;
this.Left = AbsolutePos.X - startPoint.X;
}
}
これは私のウィンドウをドラッグするために機能しますが、マウスを高速に移動すると言われたように、ウィンドウから出てイベントの発生を停止します。言及することなく、ドラッグはまったくスムーズではありません。誰もそれを適切に行う方法を知っていますか?可能であれば、私のような初心者がコードを失ってしまうようなチュートリアル全体以外の簡単な例を投稿してください。ありがとう!
Jobi Joy の回答を基に、再利用可能なソリューションを見つけました。既存のコントロール/ページのxaml内のコントロール。名前が異なるスコープを持つため、Xamlに名前を付けて追加することはできませんでした。
[ContentProperty("Child")]
[DefaultEvent("Opened")]
[DefaultProperty("Child")]
[Localizability(LocalizationCategory.None)]
public class DraggablePopup : Popup
{
public DraggablePopup()
{
MouseDown += (sender, e) =>
{
Thumb.RaiseEvent(e);
};
Thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
/// <summary>
/// The original child added via Xaml
/// </summary>
public UIElement TrueChild { get; private set; }
public Thumb Thumb { get; private set; } = new Thumb
{
Width = 0,
Height = 0,
};
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
TrueChild = Child;
var surrogateChild = new StackPanel();
RemoveLogicalChild(TrueChild);
surrogateChild.Children.Add(Thumb);
surrogateChild.Children.Add(TrueChild);
AddLogicalChild(surrogateChild);
Child = surrogateChild;
}
}