3

問題:

私のアプリケーションでは、ユーザーがチェックボックスの列を介してデータグリッド内の複数のエントリを選択できる必要があります。望ましい動作は、列のチェックボックスをクリックすると、通常のチェックボックスのように動作することですが、マウスの左ボタンを押したままドラッグすると、選択状態が以前とは逆に変わります。

私がこれまでに試したこと:

CheckBox のサブクラス化と OnMouseEnter の処理を​​試みましたが、クリックされた最初のチェックボックスがマウスをキャプチャしているように見えるため、他のチェックボックスは OnMouseEnter イベントを発生させません。

ユーザーがクリックしてチェックボックスを選択し、そのチェックボックスを他のチェックボックスにドラッグして、他のチェックボックスが DragOver イベントを受け取り、状態を切り替えることができるドラッグアンドドロップハックを実装しようとしました。この解決策により、ドラッグ アンド ドロップ中に別のチェックボックス上にないときに、カーソルがスラッシュ付きの円として表示されます。これは、このアプリケーションでは受け入れられません。

私が欲しいもの:

この機能はアプリケーションの複数の場所で必要になるため、説明した機能を備えたチェックボックスを実装するメソッドが必要です。理想的には、再利用できる xaml スタイルまたはサブクラスです。

この効果を達成するエレガントな方法はありますか?

4

2 に答える 2

3

私は自分のアプリケーションでこれを行いました。たとえば、30 個のチェックボックスを選択する必要がある場合に非常に便利です。
これを行うために、プレビュー マウス イベントを自分で処理しました: PreviewMouseLeftButtonDown、PreviewMouseMove、PreviewMouseLeftButtonUp。

PreviewMouseLeftButtonDown : コントロールに対するマウスの位置を取得します。
PreviewMouseMove で: firstPoint から十分に離れている場合、開始位置から現在の位置まで四角形を描画します。次に、CheckBoxes を反復処理し、それらが四角形と交差するかどうかを確認し、交差する場合は強調表示します (したがって、ユーザーは、どのチェック ボックスがスワップされるかを知ることができます)

それがあなたを助けることができるなら、ここに私が使用するコードがあります。MVVM (:-)) ではありませんが、問題なく動作します。アイデアが得られるかもしれません。これは、vb.net コードからの自動翻訳です。

これを機能させるには、プロパティ IsHitTestVisible="False" を使用して、CheckBoxes の上 (= たとえば同じグリッド セル内) に Canvas が必要です。
この Canvas 内に、「SelectionRectangle」という名前の Rectangle を適切な塗りと線で配置しますが、不透明度は 0.0 です。

// '' <summary>
// '' When Left Mouse button is pressed, remember where the mouse move start
// '' </summary>
private void EditedItems_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
    StartPoint = Mouse.GetPosition(this);
}

// '' <summary>
// '' When mouse move, update the highlight of the selected items.
// '' </summary>
private void EditedItems_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
    if ((StartPoint == null)) {
        return;
    }
    PointWhereMouseIs = Mouse.GetPosition(this);
    Rect SelectedRect = new Rect(StartPoint, PointWhereMouseIs);
    if (((SelectedRect.Width < 20) 
                && (SelectedRect.Height < 20))) {
        return;
    }
    //  show the rectangle again
    Canvas.SetLeft(SelectionRectangle, Math.Min(StartPoint.X, PointWhereMouseIs.X));
    Canvas.SetTop(SelectionRectangle, Math.Min(StartPoint.Y, PointWhereMouseIs.Y));
    SelectionRectangle.Width = Math.Abs((PointWhereMouseIs.X - StartPoint.X));
    SelectionRectangle.Height = Math.Abs((PointWhereMouseIs.Y - StartPoint.Y));
    foreach (CheckBox ThisChkBox in EditedItems.Children) {
        object rectBounds = VisualTreeHelper.GetDescendantBounds(ThisChkBox);
        Vector vector = VisualTreeHelper.GetOffset(ThisChkBox);
        rectBounds.Offset(vector);
        if (rectBounds.IntersectsWith(SelectedRect)) {
            ((TextBlock)(ThisChkBox.Content)).Background = Brushes.LightGreen;
        }
        else {
            ((TextBlock)(ThisChkBox.Content)).Background = Brushes.Transparent;
        }
    }
}

// '' <summary>
// '' When Left Mouse button is released, change all CheckBoxes values. (Or do nothing if it is a small move -->
// '' click will be handled in a standard way.)
// '' </summary>
private void EditedItems_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) {
    PointWhereMouseIs = Mouse.GetPosition(this);
    Rect SelectedRect = new Rect(StartPoint, PointWhereMouseIs);
    StartPoint = null;
    SelectionRectangle.Opacity = 0;
    //  hide the rectangle again
    if (((SelectedRect.Width < 20) 
                && (SelectedRect.Height < 20))) {
        return;
    }
    foreach (CheckBox ThisEditedItem in EditedItems.Children) {
        object rectBounds = VisualTreeHelper.GetDescendantBounds(ThisEditedItem);
        Vector vector = VisualTreeHelper.GetOffset(ThisEditedItem);
        rectBounds.Offset(vector);
        if (rectBounds.IntersectsWith(SelectedRect)) {
            ThisEditedItem.IsChecked = !ThisEditedItem.IsChecked;
        }
        ((TextBlock)(ThisEditedItem.Content)).Background = Brushes.Transparent;
    }
}

編集:ユーザーコントロール内でそのコードを使用しました。このコントロールは、ブール値のリストと文字列 (キャプション) のリストを引数として取り、適切なキャプションを持つ CheckBox の配列を (WrapPanel を使用して) 構築します。そのため、長方形で選択/選択解除できます。また、すべてをオン/オフするための2つのボタンもあります。また、列と行のバランスが取れた 7 ~ 200 個のブール値の選択を処理するために、列と行の比率を適切に保つようにしました。

ウィンドウ内での BooleanEdit ユーザー コントロールの使用例

于 2012-10-03T13:35:42.327 に答える
0

このトピックは数か月前のものですが、あなたが探しているエレガントな答えがあると思います.

ドラッグとチェックを 2 つの別個の動作として説明しているため、最初にデータグリッドの MouseDown ハンドラを設定します...

yourdatagrid.MouseDown += DragCheck_MouseDownHandler;

これにより、データグリッドの背景からドラッグを開始できます (ただし、グリッド内のコントロールではありません)。

    private void DragCheck_MouseDownHandler(object sender, MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;
        Control dgrid = sender as Control;
        foreach (CheckBox box in dgrid.Controls.OfType<CheckBox>())
        {
            box.Tag = null;
        }
        dgrid.MouseMove += DragMove_MouseMoveHandler;
    }

これはcheckbox.Tag、マウスがダウンしている間、1 つのパスのみをドラッグするためのトグルとして を使用します。CheckBox タグを他の目的で使用する場合は、ボックスを識別する独自の方法を見つけることができると確信しています。はdatagrid.MouseMove次のハンドラーに設定されます....

    private void DragMove_MouseMoveHandler(object sender, MouseEventArgs e)
    {
        Control dgrid = sender as Control;

        Point now = dgrid.PointToClient(Cursor.Position);
        if (e.Button == MouseButtons.Left)
        {
            Control under = dgrid.GetChildAtPoint(now);
            if (under != null && under.GetType() == typeof(CheckBox))
            {
                //if the point has a valid CheckBox control under it
                CheckBox box = under as CheckBox;
                if (box.Tag == null)// not yet been swiped
                {
                    box.Checked = !box.Checked;
                    box.Tag = true;
                }
            }
        }
        else
        {
            //if MouseButtons no longer registers as left
            //remove the handler 

            dgrid.MouseMove -= DragMove_MouseMoveHandler;

        }
    }
于 2013-07-18T07:54:58.713 に答える