5

マウス ボタンが押されている間に WPF ListBox が MouseMove イベントを取得すると、リストボックスの選択が変更されます。つまり、アイテム #1 でマウスをクリックしてアイテム #2 の上にドラッグすると、アイテム #1 の選択が解除され、代わりにアイテム #2 が選択されます。どうすればこれを防ぐことができますか?

それがショートバージョンです。少し長いバージョンは次のとおりです。ユーザーが ListBox 内の項目をダブルクリックすると、ListBox の上に他のコントロールを表示するなど、レイアウトに他の変更を加えます。これにより、ListBox が下に移動します。つまり、マウスは、ユーザーがダブルクリックしたときとは異なる ListBoxItem の上に配置されます。

DoubleClick イベント (マウスダウン イベント) に応答してこれらのレイアウト変更を行っているため、このレイアウト変更が完了したときにマウス ボタンが押されたままになる可能性が非常に高くなります。つまり、WPF は ListBox に MouseMove イベント ( ListBox に対するマウスの位置が変更されたため)。ListBox はこれをドラッグとして扱い、現在マウスの下にあるイベントを選択します。

ダブルクリックイベントを取得してからユーザーがマウスを離すまでの間に選択を変更したくありません (レイアウトが変更された後かもしれません)。これを実現する最も簡単な方法は、「ドラッグ時に選択を変更する」動作を無効にすることだと思いますが、他の提案も受け付けています。

ダブルクリックで選択を「ロック」し、マウスアップまで変更できないようにするにはどうすればよいですか?

4

1 に答える 1

20

ILSpyを調べてみると、「ドラッグして選択」動作を無効にするプロパティがないことや、それを停止するために処理済みとしてマークできるイベントがないことがわかりました。

ただし、この動作を変更するための適切な転換点があります。ListBoxItem.OnMouseEnterは仮想であり、リストボックスを呼び出して選択を変更します。それは他に実質的なことを何もしていないように見えるので、私がする必要があるのはそれをオーバーライドして何もしないことです。

編集:結局のところ、上記はリストボックス内でマウスを動かしている間だけ選択が変更されないようにします。マウスをリストボックスの上または下に移動しても役に立ちません。自動スクロールが開始され、選択範囲が移動します。自動スクロールコードのほとんどは、やはり非仮想メソッドです。自動スクロールを防ぐ最善の方法は、おそらくマウスキャプチャを無効にすることです。ListBoxItemの別のオーバーライドでこれを処理できます。

私自身のListBoxItemの子孫を使用する最良の方法は、ListBoxの子孫であるように見えます。最終的なコードは次のようになります。

public class ListBoxEx : ListBox
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ListBoxExItem();
    }
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is ListBoxExItem;
    }
}
public class ListBoxExItem : ListBoxItem
{
    private Selector ParentSelector
    {
        get { return ItemsControl.ItemsControlFromItemContainer(this) as Selector; }
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
    }
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        ParentSelector?.ReleaseMouseCapture();
    }
}
于 2011-04-14T21:40:49.330 に答える