我正在使用WPF客户端应用程序,该应用程序使用列表框来显示行程。我的任务是实现拖放功能,以重新排序工作清单中的列表项,从而重新排序行程。工作清单中的每个项目都有自己的视图和视图模型,橙色箭头(开始许可检查),红色许可证编号(在许可证上显示更多信息)和复选框(选择项目以便上传检查,或保存更改。也触发列表框视图上的按钮变为活动状态)都位于该视图中。
我使用列表框后面的代码和PreviewLeftMouseButtonDown触发器完成了拖放操作。但是,似乎前面提到的触发器消耗了复选框的触发器,而不是红色按钮或橙色按钮。列表框视图中的“全选”按钮仍然有效 以下是浓缩列表项的XAML代码,仅显示复选框代码:
<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>
以下是仍可用于比较的红色许可证编号框的代码:
<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代码:
<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>
以下是允许拖放的列表框背后的代码:
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();
}
}
感谢您提供的任何帮助,如果您需要更多信息,请告诉我们。
更新#1对尝试和结果进行故障排除 1.从复选框中删除动态样式,然后使用复选框。结果 - 复选框没有变化。似乎事件没有进入ListBox项目,除了它仍然允许点击按钮。
答案 0 :(得分:0)
因此,在详尽地搜索之后,我试图在事件发生时实现一些逻辑以消除事件的消耗。我想如果我要放一个&#39; if&#39;没有别的事件中的陈述。
我还发现我需要两个事件触发器才能执行此操作。以下是我在视图中使用的事件触发器:
<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是一个布尔值,它允许事件处理程序知道用户何时开始拖动操作。 public Point _startPoint {get;组; } public bool dragAction = false;
在PreviewMouseButtonDown事件中,我将鼠标光标的起始位置设置为_startPoint。
private void RequestCheckedOutV_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(null);
}
PreviewMouseMove处理程序是我将起点的位置与鼠标的释放位置进行比较的地方,然后将结果与系统参数中预设的最小移动规格进行比较。(我的预设为4)如果它更多那么最小值,处理程序知道它是一个Drag drop事件并调用StartDrag并将dragAction设置为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,这样如果它被错误地删除,则可以重置事件。
private void StartDrag(object sender, MouseEventArgs e)
{
ListBoxItem draggedItem = sender as ListBoxItem;
draggedItem.IsSelected = true;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
dragAction = false;
}
我的掉落处理程序根本没有变化。 我不知道这是否是实现这一目标的最佳方式,但它对我有用。我想如果它为我节省了一些时间,希望它也会帮助其他人。