单击并拖动到WPF / C#中的“多选”复选框

问题:

我的应用程序要求用户能够通过一列复选框选择数据网格中的多个条目.所需的行为是,当您单击列中的复选框时,它的行为类似于普通的复选框,但是如果在鼠标左键按下时将其拖动,其选择状态将变为以前的相反状态.

到目前为止我尝试过的是:

我尝试了子类化CheckBox并处理OnMouseEnter,但是单击的第一个复选框似乎捕获了鼠标,因此没有其他复选框触发OnMouseEnter事件.

我尝试过实施拖放式黑客,用户单击该复选框以选择一个复选框,然后将该复选框拖到其他复选框上,以便其他用户收到DragOver事件并可以切换状态.此解决方案使光标在拖放过程中未在另一个复选框上方时显示为带有斜线的圆圈,这对于此应用程序是不可接受的.

我想要的是:

我想要一种方法来实现一个具有我所描述功能的复选框,理想情况下,该功能应以我可以重用的xaml样式或子类来实现,因为在我的应用程序的多个位置都需要此功能.

有没有达到这种效果的优雅方法?

解决方法:

我在我的应用程序中执行了此操作,当您必须选择30个复选框时非常方便.
为此,我自己处理了预览鼠标事件:PreviewMouseLeftButtonDown,PreviewMouseMove,PreviewMouseLeftButtonUp.

在PreviewMouseLeftButtonDown中:我获得相对于控件的鼠标位置.
在PreviewMouseMove中:如果我距firstPoint足够远,则从开始到当前位置绘制一个矩形.然后我在CheckBoxes中进行迭代,看看它们是否与矩形相交,并高亮显示它们(这样用户就知道chexboxes将会交换)
在PreviewMouseLeftButtonUp中:我进行交换以使CheckBoxes相交.

如果可以帮助您,这是我使用的代码.它不是MVVM(:-)),但工作正常,可能会给您一些想法.它是vb.net代码的自动翻译.

为了使其工作,您需要在CheckBoxes顶部(例如,在同一网格单元内)具有属性IsHitTestVisible =“ False”的Canvas.
在此Canvas中,放置一个矩形,命名为“ SelectionRectangle”,具有适当的填充和笔触,但不透明度为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;
    }
}

编辑:我在用户控件中使用该代码.此控件将一个布尔值列表和一个字符串(标题)列表作为参数,并构建(使用WrapPanel)具有正确标题的CheckBoxes数组.因此,您可以使用矩形选择/取消选择,还有两个按钮可以全部选中/全部取消选中.我还尝试保持良好的列/行比率,以处理具有良好列/行平衡的7到200个布尔值.

上一篇:WPF DataGrid 双击行 获得绑定数据


下一篇:jQuery EasyUI DataGrid Checkbox 数据设定与取值