0

嗨尝试将我的应用程序迁移到 WPF,并且我正在尝试尽可能多地保留 MVVM。我的 WinForm 应用程序中的以下屏幕相当容易创建,我对 Xaml 和 WPF 没有这么好的运气。

WinForm 自定义字段映射的屏幕截图

我喜欢它的工作原理,但我的目标是使用 WPF 重新创建它,或者以我还没有想到的方式进行此字段映射,这仍然满足将输入字段映射到我现有数据结构的基本要求.

目前这就是我在 Xaml 中所拥有的。

<UserControl x:Class="ImportJobDataView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:kne="clr-namespace:FatigueMVVM"
         xmlns:local="clr-namespace:FatigueMVVM.DragDropListBox"                   
         mc:Ignorable="d" d:DesignHeight="350" d:DesignWidth="447">

<Grid Height="350" Width="448">

    <Grid.RowDefinitions >
        <RowDefinition Height="300" />
        <RowDefinition Height="50" />
    </Grid.RowDefinitions>

    <ListView ItemsSource="{Binding ImportedJobDataColumns}"  Margin="37,68,295,64" local:DragDropHelper.IsDragSource="true">
        <ListView.View >
            <GridView AllowsColumnReorder="True"   >
                <GridViewColumn Width="100" Header="Imported"/>
            </GridView>
        </ListView.View>
    </ListView>
    <ListView ItemsSource="{Binding KneJobDataColumns}"  Margin="193,68,41,64" AllowDrop="True" local:DragDropHelper.IsDropTarget="true">
        <ListView.View >
            <GridView AllowsColumnReorder="True"   >
                <GridViewColumn Width="100" Header="Import From" DisplayMemberBinding="{Binding ImportField }"   />
                <GridViewColumn Width="100" Header="Map To" DisplayMemberBinding="{Binding  KneField }" />
            </GridView>
        </ListView.View>
    </ListView>

    <Button Content="Open Csv" Height="23" HorizontalAlignment="Left" Margin="37,15,0,0" Name="Button1" VerticalAlignment="Top" Width="75" Command="{Binding OpenCsvCommand}" Grid.Row="1" />
    <Button Content="Clean Data" Height="23" HorizontalAlignment="Left" Margin="118,15,0,0" Name="Button2" VerticalAlignment="Top" Width="auto" Grid.Row="1" />
    <Button Content="View Imported Data" Height="23" HorizontalAlignment="Left" Margin="193,15,0,0" Name="Button3" VerticalAlignment="Top" Width="auto" Grid.Row="1" />
</Grid>

这看起来接近我希望它的外观,但我无法进行拖放工作。您可能已经注意到,我正在使用 Bea Stollnitz 解决方案来尝试实现拖放。 http://bea.stollnitz.com/blog/?p=53 她的解决方案仅适用于 ItemsControls,因此,恐怕它在我用来创建这两个的 GridView 中不起作用列。我只用列表框尝试过,拖放功能确实有效,但我确实需要两列才能完成这项工作。

在此处输入图像描述

有没有人有关于如何在这种情况下实现拖放的建议,或者我目前正在尝试实现的方式的替代方法。

非常感谢!

4

2 回答 2

1

我最终使用了 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
于 2012-07-22T05:05:52.807 回答
0

如果没有看到代码,很难说出确切的问题是什么,但是我之前使用过 Bea Stollnitz 的 DragDrop 代码,并且知道她的 DragDrop 类有几个地方将源容器或目标容器转换为一个ItemsControlListBox什至可能是一个ListBoxItem,并且仅在结果不为空时才继续。

您需要更新这些点以投射为ListView(或ListViewItem)并调整那里的逻辑以考虑 ListView 的 VisualTree(我使用Snoop在运行时查看 Visual Tree)

于 2012-07-13T13:36:18.467 回答