我最终使用了 DataGrid 而不是 ListView,主要是因为它具有我想要的更多外观。因为时间有点紧迫,因为我已经在这个问题上浪费了很多时间,所以我决定只在代码隐藏中实现拖放功能。通过阅读这篇文章改变了我对此的看法...... http://forums.silverlight.net/t/225274.aspx/1
虽然我正在处理的情况略有不同,但现在它在代码隐藏中,也许有一天我会将它移到 View-Model 中只是为了学习新的东西......如果有人不同意,并想提出一个简单的解决方案,将它移到 VM 中,做我的客人:) 下面是 UI 图像,显示了我要完成的工作,然后是 xaml,然后是代码隐藏。我从http://www.wpftutorial.net/DragAndDrop.html开始,并以此为基础工作。此功能非常特定于这一用户控件,因此虽然我对通过 MVVM 模式传递鼠标事件的一般概念感兴趣,但我不确定将其应用于这种情况会有多大用处。
想法?
<Border BorderBrush="Silver" BorderThickness="1" Grid.RowSpan="2" HorizontalAlignment="Left" Margin="5" Name="Border1" VerticalAlignment="Top" Width="Auto" Height="Auto" >
<StackPanel >
<Expander Header="Instructions" IsExpanded ="False" ExpandDirection="Down" Width="Auto" Height="Auto" >
<TextBlock Text="{Binding Instructions}" TextWrapping="Wrap" Margin="5" />
</Expander>
<Grid Height="420" Width="485">
<Grid.RowDefinitions >
<RowDefinition Height="5*" />
<RowDefinition Height="5*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="6*" />
</Grid.ColumnDefinitions>
<DataGrid AutoGenerateColumns="False" HorizontalAlignment="Stretch"
Margin="5" Name="DataGrid1" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"
ItemsSource="{Binding ImportedJobDataColumns}" SelectionUnit="Cell" CanUserReorderColumns="False"
PreviewMouseLeftButtonDown="DataGrid_MouseLeftButtonDown" MouseMove="DataGrid_MouseMove">
<DataGrid.Columns>
<DataGridTextColumn Header="Imported" Binding="{Binding Path=.}" Width="*" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
<DataGrid AutoGenerateColumns="False" HorizontalAlignment="Stretch"
Margin="5" Name="DataGrid2" VerticalAlignment="Stretch" Grid.Column="1" Grid.Row="0"
ItemsSource="{Binding KneJobDataColumns}" SelectionUnit="Cell" CanUserReorderColumns="False" AllowDrop="True"
PreviewDragOver="DataGrid_PreviewDragOver" Drop="DataGrid_Drop">
<DataGrid.Columns>
<DataGridTextColumn Header="From" Binding="{Binding Path=ImportField}" Width="*"
CanUserReorder="False" CanUserSort="False" IsReadOnly="True"/>
<DataGridTextColumn Header="To" Binding="{Binding KneField}" Width="*"
CanUserSort="False" CanUserReorder="False" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
<Grid Margin="5" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="1" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Content="Auto Map" Grid.Column="0" Name="Button4" Height="Auto" HorizontalAlignment="Stretch" Command="{Binding AutoMap}" />
<Button Content="Clear Map" Grid.Column="1" Name="Button5" Height="Auto" HorizontalAlignment="Stretch" Command="{Binding ClearMappings}"/>
<DockPanel Grid.Row="1" Grid.Column="0" >
<Label Content="Max Press." HorizontalAlignment="Left" Name="Label1" VerticalAlignment="Top" Width="Auto" />
<xctk:IntegerUpDown Value="{Binding MaxPressureInc}" Minimum="1" Increment="10"/>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="1" >
<Label Content="Min Depth" Grid.Row="1" Grid.Column="1" Height="28" HorizontalAlignment="Left" Name="Label2" VerticalAlignment="Top" Width="69" />
<xctk:IntegerUpDown Grid.Row="1" Grid.Column="1" Value="{Binding MinDepthInc}" Minimum="1" Increment="1"/>
</DockPanel>
<Button Content="Open Csv" Grid.Row="2" Grid.Column="0" Height="Auto" Name="Button1" Command="{Binding OpenCsv}" />
<Button Content="Clean Data" Grid.Row="2" Grid.Column="1" Height="Auto" Name="Button2" Command="{Binding CleanData}" />
<Button Content="View Imported Data" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Name="Button3" />
<ProgressBar HorizontalAlignment="Stretch" Name="ProgressBar1" VerticalAlignment="Stretch" Grid.Row="4" IsIndeterminate="{Binding IsBusy}"
Foreground="Blue" Background="LightGray" Visibility="{Binding IsBusy, Converter={local:BooleanToVisibilityConverter}}" Grid.ColumnSpan="2" />
<Label Content="Current File:" Grid.Column="0" Grid.Row="5" HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBlock TextWrapping="Wrap" Text="{Binding CsvFileNameCurrent}" HorizontalAlignment="Right" Name="TextBlock1"
VerticalAlignment="Center" Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" Width="Auto" />
</Grid>
</Grid>
</StackPanel>
</Border>
Public Class ImportJobDataView
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.DataContext = New ImportJobDataViewModel
End Sub
Private startPoint As Point
Private Sub DataGrid_MouseLeftButtonDown(sender As System.Object, e As System.Windows.Input.MouseButtonEventArgs)
startPoint = e.GetPosition(Nothing)
End Sub
Private Sub DataGrid_MouseMove(sender As System.Object, e As System.Windows.Input.MouseEventArgs)
'Current Mouse Position
Dim MousePos = e.GetPosition(Nothing)
Dim MouseVector As Vector = startPoint - MousePos
'Only do the following if the left moust button is held, and the cursor has moved more than the minimum horizontal distance
If (e.LeftButton = MouseButtonState.Pressed) And (MouseVector.Length > SystemParameters.MinimumHorizontalDragDistance) Then
If TypeOf e.OriginalSource Is TextBlock Then
'Get the TextBlock inside the Cell
Dim TxtBlock As TextBlock = FindAncestor(Of TextBlock)(DirectCast(e.OriginalSource, FrameworkElement))
'Initialize the drag & drop
Dim DragData As New DataObject("String", TxtBlock.Text)
DragDrop.DoDragDrop(TxtBlock, DragData, DragDropEffects.Copy)
End If
End If
End Sub
Private Sub DataGrid_PreviewDragOver(sender As System.Object, e As System.Windows.DragEventArgs)
If TypeOf e.OriginalSource Is TextBlock Then
Dim Cell As DataGridCell = FindAncestor(Of DataGridCell)(DirectCast(e.OriginalSource, DependencyObject))
'We aren't in a cell, don't allow a drop
If Cell Is Nothing Then
e.Effects = DragDropEffects.None
Exit Sub
End If
'Make sure we don't have a drop in the second column
If (Cell.Column.DisplayIndex > 0) Then
e.Effects = DragDropEffects.None
Else
e.Effects = DragDropEffects.Copy
End If
Else
e.Effects = DragDropEffects.None
End If
End Sub
Private Sub DataGrid_Drop(sender As System.Object, e As System.Windows.DragEventArgs)
If e.Data.GetDataPresent("String") Then
Dim SourceString As String = CStr(e.Data.GetData("String"))
If TypeOf e.OriginalSource Is TextBlock Then
'Write to cell contents only, so that we don't end up writing to the textblock inside the cells header row.
Dim Cell As DataGridCell = FindAncestor(Of DataGridCell)(DirectCast(e.OriginalSource, DependencyObject))
If Cell Is Nothing Then Exit Sub
Cell.Content = SourceString
End If
End If
End Sub
Private Function FindAncestor(Of T As DependencyObject)(current As DependencyObject) As T
Do
If TypeOf current Is T Then
Return DirectCast(current, T)
End If
current = VisualTreeHelper.GetParent(current)
Loop While current IsNot Nothing
Return Nothing
End Function
End Class