# Drag / Drop (Blazor)

## NuGet Package Details

**Package Name**  
[Llamachant.ExpressApp.DragDrop.Blazor](https://www.nuget.org/packages/Llamachant.ExpressApp.DragDrop.Blazor)

## Overview

This module allows you to drag / drop files on list views for any business object that implements the IFileData, IFileAttachment, or ISupportDragDrop interface, or has the FileAttachment attribute.

### 🌟 Key Features

- [Drag / Drop Templates](/content/docs/Llamachant.ExpressApp.DragDrop.Blazor#DragDropTemplates/index.html)
- [Filtering File Extensions and File Types](/content/docs/Llamachant.ExpressApp.DragDrop.Blazor#FilteringFileExtensionsAndMimeTypes/index.html)
- [ISupportDragDrop](/content/docs/Llamachant.ExpressApp.DragDrop.Blazor#ISupportDragDrop/index.html)
- [Custom Templates](/content/docs/Llamachant.ExpressApp.DragDrop.Blazor#CustomTemplates/index.html)

## Installation

### Step 1: Install the Module

```
Install-Package 'Llamachant.ExpressApp.DragDrop.Blazor'
```

### Step 2: Register the Module

```
services.AddXaf(Configuration, builder => {
    builder.UseApplication<ExpressAppBlazorApplication>();
    builder.Modules.AddLlamachantFrameworkDragDropBlazorModule();
});
```

#### IMPORTANT

This module requires you to register the module using AddLlamachantFrameworkDragDropBlazorModule() in the application builder rather than adding it to the RequiredModuleTypes collection.

#### TIP

If you are using custom templates, set the options within the AddLlamachantFrameworkDragDropBlazorModule() call.

```
services.AddXaf(Configuration, builder => {
    builder.UseApplication<ExpressAppBlazorApplication>();
    builder.Modules.AddLlamachantFrameworkDragDropModuleBlazor(options => {
        options.UseDetailFormTemplate = false;
        options.UseNestedFrameTemplate = false;
    });
});
```

## Drag / Drop Templates

When this module is added to your application, it automatically enables drag-and-drop file upload functionality on list views using two built-in templates. These templates are applied specifically for the following view contexts:

- `TemplateContext.NestedFrame`
- `TemplateContext.View`

In addition to supporting drag-and-drop, these templates also provide a clickable link that allows users to browse and select files from their computer or device, improving usability.

## Filtering File Extensions and File Types

You can restrict which files users are allowed to upload by specifying file extensions or MIME types. Behind the scenes, this feature uses a [DxFileInput](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxFileInput._members) component from DevExpress.

To control the accepted files:

- Set `DragDropAcceptedFileTypes` to define allowed MIME types (e.g., `image/png`, `application/pdf`).
- Set `DragDropAllowedExtensions` to define allowed file extensions (e.g., `.jpg`, `.docx`).

These values are automatically passed to the `AcceptedFileTypes` and `AllowedFileExtensions` properties of the `DxFileInput` control. Make sure to follow the DevExpress guidelines for formatting these values.

## ISupportDragDrop

If your class does not implement IFileData, IFileAttachment, or use the 
[FileAttachment] attribute, you can still support drag-and-drop functionality by implementing the ISupportDragDrop interface.

```csharp
namespace LlamachantFramework.DragDrop.Blazor.Interfaces;

public interface ISupportDragDrop
{
    void LoadFromStream(string filename, Stream stream);
}
```

When a file is dropped, an instance of your class is created and the LoadFromStream method is called. This gives you control over how the file content is handled.

## Example: Parsing a Dropped Text File

In the following example, a text file is dropped onto the Contacts list view. The file contents are parsed to populate the Name, EmailAddress, and PhoneNumber properties of a new Contact object.

```csharp
using LlamachantFramework.DragDrop.Blazor.Interfaces;

public class Contact(Session session) :
    BaseObject(session), ISupportDragDrop
{

private string _Name;
    public string Name
    {
        get { return _Name; }
        set { SetPropertyValue<string>(nameof(Name), ref _Name, value); }
    }

private string _PhoneNumber;
    public string PhoneNumber
    {
        get { return _PhoneNumber; }
        set { SetPropertyValue<string>(nameof(PhoneNumber), ref _PhoneNumber, value); }
    }

private string _EmailAddress;
    public string EmailAddress
    {
        get { return _EmailAddress; }
        set { SetPropertyValue<string>(nameof(EmailAddress), ref _EmailAddress, value); }
    }

private Client _Client;
    [Association]
    public Client Client
    {
        get { return _Client; }
        set { SetPropertyValue<Client>(nameof(Client), ref _Client, value); }
    }

public void LoadFromStream(string filename, Stream stream)
    {
        using StreamReader reader = new StreamReader(stream);
        string content = reader.ReadToEnd();

List<string> lines = content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();

Name = lines.FirstOrDefault(x => x.StartsWith("name:", StringComparison.InvariantCultureIgnoreCase))?.Substring(5);
        EmailAddress = lines.FirstOrDefault(x => x.StartsWith("email:", StringComparison.InvariantCultureIgnoreCase))?.Substring(6);
        PhoneNumber = lines.FirstOrDefault(x => x.StartsWith("phone:", StringComparison.InvariantCultureIgnoreCase))?.Substring(6);
    }
}
```

### Notes

- **Security**: Always validate the file content to avoid malicious input. You may want to restrict parsing to expected formats only.
- **Error Handling**: Consider wrapping file parsing in try-catch blocks to handle malformed data or unexpected errors gracefully.
- **Logging**: Adding basic logging can help track dropped file activity and diagnose issues.
