XAMLで始めるWPF入門:ドラッグ&ドロップでファイルを渡す。その2

コンピュータ

前回はコントロールのTagを使いドラッグ&ドロップされたファイルの一覧を渡していましたが、コードビハインドからViewModelのメソッドを呼び出しても良いとのことですので、変更してみました。

直接呼び出しだと依存度が高そうなので、申し訳程度にインターフェイスを経由するようにしてあります。

ソースコード

ファイル名:dd01.csproj


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

ファイル名:MainWindow.xaml.cs


using System.Collections.ObjectModel;
using System.Windows;
using Microsoft.VisualBasic;
using NxLib.Helper;

namespace dd01;

public partial class MainWindow : Window
{
    
    public MainWindow()
    {
        InitializeComponent();

        var vm = new MainViewModel();
        DataContext = vm;

        Wiring.AcceptFiles(DdArea, files =>
        {
            (DataContext as IAcceptFiles)?.SetFiles(files);
        });
    }
}

ファイル名:Helpers\Wiring.cs


using System.Windows;

namespace NxLib.Helper;
public static class Wiring
{
    // D&D: 指定拡張子だけ受け付ける(exts 省略可)
    public static void AcceptFiles(FrameworkElement el, Action<string[]> onFiles, params string[] exts)
    {
        el.AllowDrop = true;
        el.Drop += (_, e) =>
        {
            if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;

            var files = (string[])e.Data.GetData(DataFormats.FileDrop)!;

            if (exts is { Length: > 0 })
                files = files
                    .Where(f => exts.Any(x => f.EndsWith(x, StringComparison.OrdinalIgnoreCase)))
                    .ToArray();

            if (files.Length > 0)
                onFiles(files);
        };
    }
}

ファイル名:ViewModels\IAcceptFiles.cs


namespace dd01;

public interface IAcceptFiles
{
    void SetFiles(IEnumerable<string> files);
}

ファイル名:ViewModels\MainViewModel.cs


using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;


namespace dd01;

public class MainViewModel : INotifyPropertyChanged, IAcceptFiles
{
    public ObservableCollection<string> Files { get; private set; } = [];
    private string _message = "こちらにドラック&ドロップしてください。";
    public string Message
    {
        get => _message;
        set
        {
            if (_message != value)
            {
                _message = value;
                OnPropertyChanged();
            }
        }
    }
    public MainViewModel()
    {
    }
    public void SetFiles(IEnumerable<string> files)
    {
        Files.Clear();
        foreach (var s in files) Files.Add(s);
        Message = string.Join(Environment.NewLine, Files);
    }
    public event PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

ファイル名:MainWindow.xaml

<Window x:Class="dd01.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:dd01"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TextBlock
            x:Name="DdArea"
            Text="{Binding Message}"
            FontSize="24"
            TextAlignment="Center"
            TextWrapping="Wrap"
            HorizontalAlignment="Center"
            VerticalAlignment="Center" />
    </Grid>
</Window>

実行イメージ

コメント