【解決方法】WPF データグリッドのスクロールバーの問題。

[ad_1]

皆さん、こんにちは:
私はドラッグアンドドロップの例に従っています:
https://www.c-sharpcorner.com/UploadFile/raj1979/drag-and-drop-datagrid-row-in-wpf/ しかし、スクロールバー (水平または垂直) を使用すると問題が発生することがあります。
例のデータではなく、多数の列と多数の行を持つテーブルのデータを使用しています。
コード例では、GetMouseTargetRow プロシージャで、スクロールバー ボタン (水平または垂直) を移動しているときに、データグリッドのセル領域の外側をクリックしているかどうかがわかります。
しかし、列がデータグリッド領域の幅を超えている場合、GetMouseTargetRow プロシージャは、スクロールバーに触れたことを認識しないため、false を返します。 すべての列を小さくして、データ グリッドの幅よりも少ない領域を占めるようにすると、すべて正常に機能します。
水平スクロールバーを移動すると、同じことが起こります。これは、データグリッドがクラッシュして列の幅を調整できない場合があるためです。
私のテストとの唯一の違いは、私の XAML コードでは、データグリッドで d:LayoutOverrides=”Width” を使用していないことです。 それは問題を説明していますか? LayoutOverride は何に使用されますか?
助けてくれてありがとう。

私が試したこと:

これは私の最初の WPF データグリッド テストです。

解決策 2

簡単な解決策へのリンクを提供したかったのです。 これは不可能であることが判明しました。

そのため、次のリンクから解決策を採用しました。
* WPF で DataGrid 行をドラッグ アンド ドロップする[^] = 最初の試み – ドラッグ アンド ドロップの良い解決策ではありません!
* WPF チュートリアル | ドラッグドロップ[^] = Drag’n’Drop を実装するより良い方法ですが、コントロールが間違っています
* WPF: ドラッグ & ドロップ中にコントロールの内容をスクロールする[^] =例のない実用的な解決策

1. ScrollOnDragOverBehavior 上記のリンクから変更する必要はありませんでしたので、そこからコードを取得してください。

2. ObservableObject をラッピングするクラス INotifyPropertyChanged

C#
public abstract class ObservableObject : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
    {
        if (!EqualityComparer<TValue>.Default.Equals(field, default) && field!.Equals(newValue))
            return;

        field = newValue;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler? PropertyChanged;
}

3. Employee データ・モデル:

C#
public class EmployeeModel : ObservableObject
{
    private int empNo;
    private string empName;
    private int salary;

    public int EmpNo
    {
        get => empNo;
        set => Set(ref empNo, value);
    }

    public string EmpName
    {
        get => empName;
        set => Set(ref empName, value);
    }

    public int Salary
    {
        get => salary;
        set => Set(ref salary, value);
    }
}

4. MainWindow コードビハインド

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        InitData();

        DataGrid.PreviewMouseLeftButtonDown += OnPreviewMouseLeftButtonDown;
        DataGrid.MouseMove += OnMouseMove;
        DataGrid.DragEnter += OnDragEnter;
        DataGrid.Drop += OnDrop;
    }

    private void InitData()
    {
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
            Employees.Add(new() { EmpNo = 101, EmpName = "Yudhistir", Salary = 56000 });
            Employees.Add(new() { EmpNo = 102, EmpName = "Bhim", Salary = 36000 });
            Employees.Add(new() { EmpNo = 103, EmpName = "Arjun", Salary = 45000 });
            Employees.Add(new() { EmpNo = 104, EmpName = "Sahedev", Salary = 24000 });
            Employees.Add(new() { EmpNo = 105, EmpName = "Nakul", Salary = 22000 });
    }

    public ObservableCollection<EmployeeModel> Employees { get; set; } = new();

    private Point startPoint;

    // Store the mouse position
    private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        => startPoint = e.GetPosition(null);

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        // Get the current mouse position
        Point mousePos = e.GetPosition(null);
        Vector diff = startPoint - mousePos;

        if (e.LeftButton == MouseButtonState.Pressed &&
            (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
            Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
        {
            // Get the dragged DataGridRow
            DataGridRow row = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
            
            // Find the data behind the DataGridRow
            EmployeeModel employee = (EmployeeModel)DataGrid.ItemContainerGenerator.ItemFromContainer(row);

            // Initialize the drag & drop operation
            DataObject dragDataObject = new DataObject("DataRow", employee);
            DragDrop.DoDragDrop(row, dragDataObject, DragDropEffects.Move);
        }
    }

    private void OnDragEnter(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent("DataRow") && sender != e.Source)
            return;

        e.Effects = DragDropEffects.None;
    }

    private void OnDrop(object sender, DragEventArgs e)
    {
        if (!e.Data.GetDataPresent("DataRow"))
            return;
         
        EmployeeModel source = e.Data.GetData("DataRow") as EmployeeModel;

        // Get the destination DataGridRow
        var row = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
            
        // Find the data behind the DataGridRow
        var destination = (EmployeeModel)DataGrid.ItemContainerGenerator.ItemFromContainer(row);

        // Move the EmployeeModel in the collection
        Employees.RemoveAt(Employees.IndexOf(source));
        Employees.Insert(Employees.IndexOf(destination) + 1, source);
    }

    // Helper to search up the VisualTree
    private static T FindAncestor<T>(DependencyObject current)
        where T : DependencyObject
    {
        do
        {
            if( current is T dependencyObject )
                return dependencyObject;

            current = VisualTreeHelper.GetParent(current);
        }
        while (current != null);

        return null;
    }
}

5. MainWindow XAML/UI

C#
<Window x:Class="WpfScrollOnDragOverBehavior.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfScrollOnDragOverBehavior"
        mc:Ignorable="d"
        x:Name="Window"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox HorizontalAlignment="Stretch" Margin="10" 
                 Text="EmployeeModel Information"
                 TextAlignment="Center" FontFamily="SimSun" 
                 FontSize="28" />

        <DataGrid x:Name="DataGrid"
                  Grid.Row="1"
                  ItemsSource="{Binding ElementName=Window, Path=Employees}"
                  AutoGenerateColumns="False"
                  HorizontalAlignment="Stretch" Margin="10"
                  ColumnWidth="*"
                  SelectionMode="Extended"
                  AllowDrop="True"
                  local:ScrollOnDragOverBehavior.IsScrollOnDragOverEnabled="True">
            <DataGrid.Columns>
                <DataGridTextColumn 
                    Binding="{Binding EmpNo}"
                    Header="ProductId"></DataGridTextColumn>
                <DataGridTextColumn
                    Binding="{Binding EmpName}"
                    Header="ProductName"></DataGridTextColumn>
                <DataGridTextColumn
                    Binding="{Binding Salary}"
                    Header="ProductPrice"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>
</Window>

をドラッグすると DataGridRow の端に DataGridDataGrid スクロールします。 ドロップすると、ドラッグ中のアイテムがドロップします 対象の行。

ボーナス

マウスカーソルの横にドラッグされている行を表示したい場合は、Josh の優れた記事をご覧ください。 WPF ListView で項目をドラッグ アンド ドロップする[^] – この質問の範囲外なので、これはあなたに任せます。

[ad_2]

コメント

タイトルとURLをコピーしました