[C# WPF] ファイルドラッグ&ドロップ中のマウスカーソル更新

マウスオーバーしている領域によって受け付けるファイルを変えたい。

ついでにドラッグしているファイルに合わせてマウスオーバーしたときにマウスカーソルも切り替えたい。

という私の要望に答えます。

エクスプローラからのファイルドラッグ&ドロップについてはこちらで説明しています。

このページのサンプルコードも上記を引き継いでいるので、よくわからない場合は先にご覧ください。

スポンサーリンク

環境

  • Visual Studio 2019
  • .NET Framework 4.7.2

領域ごとに受け付けるファイルを区別して、マウスカーソルも変える

サンプルコードには、MainViewとDropViewの2つのViewがあります。

どちらにもファイルドロップできるようにします。

この上で.pngはMainViewにだけ、.jpgはDropViewにだけドロップできるようにします。

このとき、ドロップできないエリアにマウスオーバーしているときには駐車禁止のカーソルになるようにします。

まずはサンプルコードです。

DragEnterとDragOverの中身が一緒ですが、関数化するより読みやすいかなと思ってそのままにしてます(言い訳

・MainView.xaml

<Window x:Class="Sample_FileDrop.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:Sample_FileDrop"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        Background="Gray"
        AllowDrop="True"
        Drop="Window_Drop"
        DragEnter="Window_DragEnter"
        DragOver="Window_DragOver"
        >

    <local:DropView Height="200" Width="400"
                    HorizontalAlignment="Center" VerticalAlignment="Center"
                    Background="White"
                    />

</Window>

・MainView.xaml.cs

using System.Windows;
using System.Windows.Media;

namespace Sample_FileDrop
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private string GetExtension(IDataObject data)
        {
            if (data == null)
            {
                return null;
            }

            // ドロップしたファイルのパスを取得する
            // 複数の場合があるので配列になります
            var paths = data.GetData(DataFormats.FileDrop) as string[];
            if (paths == null || paths.Length != 1)
            {
                return null;
            }

            // ファイルの拡張子を取得する
            var ext = System.IO.Path.GetExtension(paths[0]).ToLower();
            if (string.IsNullOrEmpty(ext))
            {
                return null;
            }
            else
            {
                return ext;
            }
        }

        private void Window_Drop(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".png":
                        // 拡張子がPNGだったら,背景色を赤にする
                        Background = Brushes.Red;
                        break;
                    default:
                        // その他の拡張子だったら,背景色を白にする
                        Background = Brushes.White;
                        break;
                }
            }
        }

        private void Window_DragEnter(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".png":
                        e.Effects = DragDropEffects.All;
                        break;
                    default:
                        e.Effects = DragDropEffects.None;
                        break;
                }

                e.Handled = true;
            }
        }

        private void Window_DragOver(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".png":
                        e.Effects = DragDropEffects.All;
                        break;
                    default:
                        e.Effects = DragDropEffects.None;
                        break;
                }

                e.Handled = true;
            }
        }
    }
}

・DropView.xaml

<UserControl x:Class="Sample_FileDrop.DropView"
             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:local="clr-namespace:Sample_FileDrop"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800"
             AllowDrop="True"
             Drop="DropView_Drop"
             DragEnter="DropView_DragEnter"
             DragOver="DropView_DragOver"
             >
</UserControl>

・DropView.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Sample_FileDrop
{
    public partial class DropView : UserControl
    {
        public DropView()
        {
            InitializeComponent();
        }

        private string GetExtension(IDataObject data)
        {
            if (data == null)
            {
                return null;
            }

            // ドロップしたファイルのパスを取得する
            // 複数の場合があるので配列になります
            var paths = data.GetData(DataFormats.FileDrop) as string[];
            if (paths == null || paths.Length != 1)
            {
                return null;
            }

            // ファイルの拡張子を取得する
            var ext = System.IO.Path.GetExtension(paths[0]).ToLower();
            if (string.IsNullOrEmpty(ext))
            {
                return null;
            }
            else
            {
                return ext;
            }
        }

        private void DropView_Drop(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".jpg":
                        // 拡張子がJPGだったら,背景色を緑にする
                        Background = Brushes.Green;
                        break;
                    default:
                        // その他の拡張子だったら,背景色を白にする
                        Background = Brushes.White;
                        break;
                }

                e.Handled = true;
            }
        }

        private void DropView_DragEnter(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".jpg":
                        e.Effects = DragDropEffects.All;
                        break;
                    default:
                        e.Effects = DragDropEffects.None;
                        break;
                }

                e.Handled = true;
            }
        }

        private void DropView_DragOver(object sender, DragEventArgs e)
        {
            // ファイルドロップを判定する
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
            {
                // ファイルの拡張子を取得する
                var ext = GetExtension(e.Data);

                switch (ext)
                {
                    case ".jpg":
                        e.Effects = DragDropEffects.All;
                        break;
                    default:
                        e.Effects = DragDropEffects.None;
                        break;
                }

                e.Handled = true;
            }
        }
    }
}

解説

設定が必要な項目は2つです。

  • DragDropEffectsを更新する
  • HandledをTrueにすることで以降のイベントハンドラの処理を抑制する

DragDropEffectsを更新する

(結果的に)マウスカーソルが変わるのがこのプロパティです。

ファイルドラッグ中のマウスカーソルの更新ですが、Cursorプロパティを変更してもできません。

DragEventArgsのEffestsプロパティを変えると、マウスカーソルも変わります。

Microsoft Docs – DragDropEffectsにはそんなことはどこにも書いていないように見えますが変わります。

「Specifies the effects of a drag-and-drop operation.」と言っているのでマウスカーソルの更新もeffectに含まれているのだと思います。

HandledをTrueにすることで以降のイベントハンドラの処理を抑制する

DragDropEffectsを書き換えるだけだとマウスカーソルが元に戻ってしまいます。

どうも以降に呼び出されているDropイベントで書き換えられてしまっているようなので、HandledにTrueを代入することで以降の呼び出しを抑制します。

これでファイルドラッグ中のマウスカーソル更新ができるようになりました。

おしまい。

スポンサーリンク

C#, WPFC#, WPF

Posted by peliphilo