0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.NET MAUIAdvent Calendar 2024

Day 1

MAUI でドラッグ&ドロップしたい!

Last updated at Posted at 2024-11-30

.NET MAUI Advent Calendar 2024 1日目の記事です。

TL;DR;

これ: https://learn.microsoft.com/dotnet/maui/fundamentals/gestures/drag-and-drop#drag-and-drop-between-applications

やりたいこと

アプリケーションにファイルを投げ込んで、そのファイルを表示させたいと思ったことはありますか?

MAUI Drag and Drop とかで調べてみると、アプリケーション内の画像をドラッグアンドドロップで移動するチュートリアルが出てきますが、それではなく**アプリケーションの外からファイルを読み込みたい!!**という内容です。

スクリーンショット 2024-12-01 012821.png

この資料では、使い方のみ解説しています。詳細は公式ドキュメントをご覧ください。

(.NET 8 以上で動きます)

動かす

テンプレートの MAUI アプリケーションを作成します。

UI 部分

画像とラベル部分を以下のように変更します。

  <Image
+     x:Name="image"
      Source="dotnet_bot.png"
      HeightRequest="185"
      Aspect="AspectFit"
-     SemanticPropeties.Description="dot net bot in a race car number eight" />
+     SemanticPropeties.Description="dot net bot in a race car number eight">
+     <Image.GestureRecognizers>
+         <DropGestureRecognizer Drop="OnDropGestureRecognizerDrop" />
+     </Image.GestureRecognizers>
+ </Image>

  ...

  <Label
      Text="Hello, World!"
+     x:Name="path"
      ... />

ドラッグアンドドロップは GestureRecognizers を利用します。

今回は、画像部分にはドロップされた画像を、テキスト部分にはドロップされたファイルのパスを表示するため、x:Name で識別子をつけておきます。

処理部分

コード (C#) 側は、以下のようにします。

#if WINDOWS
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
#elif IOS || MACCATALYST
using UIKit;
using Foundation;
using System.Diagnostics;
#endif

async void OnDropGestureRecognizerDrop(object? sender, DropEventArgs e)
{
    var filePaths = new List<string>();

    #if WINDOWS
    if (e.PlatformArgs is not null && e.PlatformArgs.DragEventArgs.DataView.Contains(StandardDataFormats.StorageItems))
    {
        var items = await e.PlatformArgs.DragEventArgs.DataView.GetStorageItemsAsync();
        if (items.Any())
        {
            foreach (var item in items)
            {
                if (item is StorageFile file)
                    filePaths.Add(item.Path);
            }
        }
    }
    #elif IOS || MACCATALYST
    var session = e.PlatformArgs?.DropSession;
    if (session == null)
        return;

    foreach (UIDragItem item in session.Items)
    {
        var result = await LoadItemAsync(item.ItemProvider, item.ItemProvider.RegisteredTypeIdentifiers.ToList());
        if (result is not null)
            filePaths.Add(result.FileUrl?.Path!);
    }
    foreach (var item in filePaths)
    {
        Debug.WriteLine($"Path: {item}");
    }

    static async Task<LoadInPlaceResult?> LoadItemAsync(NSItemProvider itemProvider, List<string> typeIdentifiers)
    {
        if (typeIdentifiers is null || typeIdentifiers.Count == 0)
            return null;

        var typeIdent = typeIdentifiers.First();

        if (itemProvider.HasItemConformingTo(typeIdent))
            return await itemProvider.LoadInPlaceFileRepresentationAsync(typeIdent);

        typeIdentifiers.Remove(typeIdent);
        return await LoadItemAsync(itemProvider, typeIdentifiers);
    }
    #endif

    // string filePath = filePaths.FirstOrDefault();

    // Process the dropped file
    path.Text = filePaths.FirstOrDefault();
    image.Source = filePaths.FirstOrDefault();
}

(公式ドキュメントのものを改変)

コードを見てわかるとおり、Windows と iOS + macOS で異なる処理をしてファイルを読み込んでいます。(Android は非対応)

複数のファイルがドロップされることがあるため、List として管理 (var filePaths = new List<string>();) し、表示の際には1番目のファイル (filePaths.FirstOrDefault()) を利用しています。

結果

このサンプルを動かすと以下のようになります。

スクリーンショット 2024-12-01 012821.png

(画像ファイルをドロップする)

スクリーンショット 2024-12-01 014653.png

(画像が変更され、画像のパスが表示される)

以上です。

先程の

path.Text = filePaths.FirstOrDefault();
image.Source = filePaths.FirstOrDefault();

だった部分を別の処理に変えることで、ドロップされたファイルを簡単に操作できますよ!

その他

何故かよくわからないけど、Intellisence があんまうまく効いていないみたいです。

スクリーンショット 2024-12-01 014609.png

(XAML のほうで <DropGestureRecognizer Drop="OnDropGestureRecognizerDrop" /> と設定しているのに、OnDropGestureRecognizerDrop が使われていないという警告が出ています。現在の .NET 9 でも直っていないです)

最後に

この方法を見つけるのに半年以上かかりました…

もともと .NET 9 での新機能 (タイトルバーのカスタマイズとか) で書こうと思っていたのですが、試す時間がなくてやめました。結構便利そうなので今度試してみたいですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?