从具有拖放功能的列表框中触发列表项上的 WPF 复选框 [英] Trigger WPF Checkbox on List Item from ListBox that has Drag and Drop

查看:66
本文介绍了从具有拖放功能的列表框中触发列表项上的 WPF 复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 WPF 客户端应用程序,该应用程序使用列表框显示行程.我的任务是实现拖放功能以重新排序工作列表中的列表项,从而重新排序行程.工作列表中的每个项目都有自己的视图和视图模型,橙色箭头(开始许可证检查)、红色许可证编号(显示有关许可证的更多信息)和复选框(选择项目以查看许可证)上传检查或保存更改.也会触发列表框视图上的按钮变为活动状态)都位于该视图中.

I am working with a WPF client application that uses a list box to display an itinerary. my task is to implement a drag and drop functionality to reorder the list items in the work list, thereby reordering the itinerary. Each of the items in the work list has its own view and viewmodel, and the orange arrow(starts a permit inspection), the red permit number(brings up more info on the permit) and the check box(selects the item in order to upload the inspection, or save changes. also triggers the buttons on the list box view to become active) are all located in that view.

我已经使用列表框后面的代码和 PreviewLeftMouseButtonDown 触发器完成了拖放操作.然而,上述触发器似乎消耗了复选框的触发器,而不是红色按钮或橙色按钮.尽管如此,列表框视图上的全选"按钮仍然有效.
以下是压缩为仅显示复选框代码的列表项的 XAML 代码:

I have accomplished the drag and drop using the code behind on the listbox, and the PreviewLeftMouseButtonDown trigger. However it seems that the aforementioned trigger consumed the trigger for the checkbox, but not the red button or the orange button. the "Select All" button on the list box view still works though.
Here is the XAML code for the list item condensed to only show the checkbox code:

<StackPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="3">
        <CheckBox  ClickMode="Press" IsTabStop="False" Style="{DynamicResource CheckBoxStyle}" HorizontalAlignment="Left" VerticalAlignment="Top" IsChecked="{Binding IsSelected,Mode=TwoWay,FallbackValue='False'}" Margin="0 2 0 0"></CheckBox>
        <Border   BorderBrush="{DynamicResource GrayBorder}" BorderThickness="0 0 1 0"/>
    </StackPanel>

这里是红色许可证号码框的代码,仍然可以用于比较:

Here is the code for the red permit number box that still works for comparison:

 <StackPanel Grid.Row="0" Grid.Column="1" Margin="4 4 4 4">
        <StackPanel Orientation="Horizontal">
            <Button IsTabStop="False" ClickMode="Press" Command="{Binding PermitDetailViewCommand}" CommandParameter="{Binding RequestInfo.PermitNumber}"  Style="{StaticResource PermitDetailButton}" Content="{Binding RequestInfo.PermitNumber, Mode=OneTime,FallbackValue=''}"/>
            <Button Style="{StaticResource CriticalIconStyle}" Visibility="{Binding RequestInfo.IsCritical, Converter={StaticResource BooleanToVisibility}}" Margin="0,4,0,0" ToolTip="{Binding RequestInfo.CriticalInformation}" Height="14" IsTabStop="False"/>
            <Button Style="{StaticResource ContactIconStyle}" Content="{Binding RequestInfo.ContactAttemptedCountCode}" Visibility="{Binding RequestInfo.ContactAttemptedCountCode, Converter={StaticResource StringToVisibility}}" Margin="0,2,0,0" IsTabStop="False"/>
        </StackPanel>
    </StackPanel>

以下是实例化列表框中每个项目的 XAML 代码:

Here is the XAML code that instantiates each item in the list box:

        <ListBox Margin="4,8" ItemsSource="{Binding Path=CheckedOutVM,Mode=TwoWay,IsAsync=True}"
              SelectedItem="{Binding Path=SelectedLocalPermit}" Grid.Row="1" Grid.Column="0" BorderThickness="0"  
              KeyboardNavigation.TabNavigation="Continue" Name="RequestCheckedOutV" BorderBrush="{DynamicResource DarkBorder}" attprop:ArrowKeyPressed.IsEnabled="True">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ClickMode.Press">
                <cmd:EventToCommand
                    Command="{Binding SelectedLocalCommand}"
                    CommandParameter="{Binding SelectedItem}"
               />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">

                <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="Control.HorizontalContentAlignment" Value="Center"/>
                <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                <Setter Property="Control.VerticalContentAlignment" Value="Top"/>
                <Setter Property="AllowDrop" Value="True"/>

                <EventSetter Event="PreviewMouseLeftButtonDown" Handler="S_PreviewMouseLeftButtonDown"/>
                <EventSetter Event="Drop" Handler="listbox1_Drop"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}"  >
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate >
                <ContentControl  Content="{Binding}" IsTabStop="False"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

这是列表框后面允许拖放的代码:

Here is the code behind on the list box to allow drag and drop:

 public partial class WorklistSmallView : UserControl
{
    WorklistSmallViewModel vm = new WorklistSmallViewModel();
    /// <summary>
    /// Initializes a new instance of the WorklistSmallView class.
    /// </summary>
    public WorklistSmallView()
    {
        InitializeComponent();
    }
    private void S_PreviewMouseLeftButtonDown(object sender, MouseEventArgs e)
    {
        WorklistSmallViewModel vm = new WorklistSmallViewModel();

        ListBoxItem draggedItem = sender as ListBoxItem;
            draggedItem.IsSelected = true;
            DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
            vm = RequestCheckedOutV.DataContext as WorklistSmallViewModel;
         }



    }

    void listbox1_Drop(object sender, DragEventArgs e)
    {

        WorklistSmallDetailViewModel droppedData = e.Data.GetData(typeof(WorklistSmallDetailViewModel)) as WorklistSmallDetailViewModel;
        WorklistSmallDetailViewModel target = ((ListBoxItem)(sender)).DataContext as WorklistSmallDetailViewModel;

        int removedIdx = RequestCheckedOutV.Items.IndexOf(droppedData);
        int targetIdx = RequestCheckedOutV.Items.IndexOf(target);


        if (removedIdx < targetIdx)
        {
            vm = (WorklistSmallViewModel)RequestCheckedOutV.DataContext;

            vm.CheckedOutVM.Insert(targetIdx + 1, droppedData);
            vm.CheckedOutVM.RemoveAt(removedIdx);
        }
        else
        {
            int remIdx = removedIdx + 1;
            if (vm.CheckedOutVM.Count + 1 > remIdx)
            {
                vm.CheckedOutVM.Insert(targetIdx, droppedData);
                vm.CheckedOutVM.RemoveAt(remIdx);
            }
        }

        foreach (var item in vm.CheckedOutVM)
        {
            item.RouteOrder = RequestCheckedOutV.Items.IndexOf(item) + 1;
        }
        RequestCheckedOutV.Items.Refresh();
    }
}

感谢您提供的任何帮助,如果您需要更多信息,请告诉我.

I appreciate any help that is offered and if you need any more info please let me know.

Update#1 故障排除尝试和结果1.从复选框中删除动态样式并使用复选框.结果 - 复选框没有变化.似乎事件没有进入 ListBox 项目,除了它仍然允许点击按钮.

Update#1 Troubleshooting attempts and results 1. Remove the dynamic style from the checkbox and use the checkbox. Results- No change in the checkbox. seems the event isnt making it to the ListBox Item, except it is still allowing the buttons to be clicked.

  1. 在列表框中将事件更改为 MouseLeftButtonDown 事件.结果 复选框有效,拖放功能无效.似乎 PreviewMouseEvent 与普通 MouseEvent 的时间是允许拖放工作的原因.

推荐答案

所以经过彻底搜索,我尝试在事件发生时实现一些逻辑,以消除事件的消耗.我想如果我要在没有 else 的情况下在事件中放置一个if"语句.

So after searching exhaustively, i tried to implement some logic when the events occur to eliminate the consumption of the event. I figured that if I were to put an 'if' statement in the event without an else.

我还发现我需要两个事件触发器来做到这一点.所以这里是我在视图中使用的事件触发器:

I also found that I needed two event triggers to do this. So here are the event triggers that i used in the view:

 <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">

                <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
                <Setter Property="Background" Value="Transparent" />
                <Setter Property="Control.HorizontalContentAlignment" Value="Center"/>
                <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                <Setter Property="Control.VerticalContentAlignment" Value="Top"/>
                <Setter Property="AllowDrop" Value="True"/>
                <EventSetter Event="PreviewMouseLeftButtonDown" Handler="RequestCheckedOutV_PreviewMouseLeftButtonDown"/>
                <EventSetter Event="PreviewMouseMove" Handler="RequestCheckedOutV_PreviewMouseMove"/>
                <EventSetter Event="Drop" Handler="listbox1_Drop"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}"  >
                            <ContentPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

            </Style>
        </ListBox.ItemContainerStyle>

然后,在后面的代码中,我完成了拖放的所有逻辑,以便在不消耗事件的情况下移动项目:首先,我需要创建 2 个局部变量以在整个代码后面使用._startPoint 是用于比较运动的 x,y 点位置.dragAction 是一个布尔值,它让事件处理程序知道用户何时开始拖动操作.公共点_startPoint { 获取;放;}public bool dragAction = false;

Then, in the code behind, I did all of the logic for the drag and drop in order to move the item without consuming the event: First i needed to create 2 local variables to use throughout the code behind. The _startPoint is a x,y point location that is used to compare movement. the dragAction is a boolean that lets the event handler know when the user is starting a drag action. public Point _startPoint { get; set; } public bool dragAction = false;

在 PreviewMouseButtonDown 事件中,我将鼠标光标的起始位置设置为 _startPoint.

In the PreviewMouseButtonDown event i set the starting location of the Mouse cursor to _startPoint.

    private void RequestCheckedOutV_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _startPoint = e.GetPosition(null);
    }

PreviewMouseMove 处理程序是我将起点的位置与鼠标的释放位置进行比较的地方,然后将结果与系统参数中预设的最小移动规格进行比较.(我的预设为 4)如果超过最低限度,处理程序知道这是一个拖放事件并调用 StartDrag 并将 dragAction 设置为 true.

The PreviewMouseMove handler is where I compare the location of the starting point to the release location of the mouse, then compare the results to the minimum movement specs preset in the system parameters.(mine was preset to 4) If its more that the minimum, the handler knows it is a Drag drop event and calls the StartDrag and sets the dragAction to true.

    private void RequestCheckedOutV_PreviewMouseMove(object sender, MouseEventArgs e)
    {

        if (Mouse.LeftButton == MouseButtonState.Pressed && !dragAction)
        {
            Point position = e.GetPosition(null);
            if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||

                Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)

            {
                dragAction = true;
                this.StartDrag(sender, e);
            }
        }
    }

下面的 StartDrag 方法实际上调用了 DoDragDrop 方法.然后它还将拖动动作变量重置为 false,以便如果它被错误放置,则可以重置事件.

the StartDrag method below actually calls the DoDragDrop method. then it also resets the drag action variable to false so that if it is dropped in error, the Events can be reset.

    private void StartDrag(object sender, MouseEventArgs e)
    {

        ListBoxItem draggedItem = sender as ListBoxItem;
        draggedItem.IsSelected = true;
        DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
        dragAction = false;
    }

我的 drop Handler 根本没有改变.我不知道这是否是实现这一目标的最佳方式,但它对我有用.我想如果它为我节省了一些时间,希望它也能帮助其他人.

My drop Handler didnt change at all. I dont know if this is the best way to make this happen, but it worked for me. i figure if it saves some time for me, hopefully it will help others out too.

这篇关于从具有拖放功能的列表框中触发列表项上的 WPF 复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆