Browse Source

Remove SystemDialog

pull/20617/head
Julien Lebosquain 1 day ago
parent
commit
0bc6247ba3
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 9
      samples/ControlCatalog/Pages/DialogsPage.xaml
  2. 95
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  3. 25
      src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs
  4. 70
      src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs
  5. 206
      src/Avalonia.Controls/SystemDialog.cs
  6. 20
      src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs

9
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -49,15 +49,6 @@
<Button Name="OpenFolderFromBookmark">Open Folder Bookmark</Button>
</StackPanel>
</Expander>
<Expander Header="Legacy OpenFileDialog">
<StackPanel Spacing="4">
<Button Name="OpenFile">_Open File</Button>
<Button Name="OpenMultipleFiles">Open _Multiple File</Button>
<Button Name="SaveFile">_Save File</Button>
<Button Name="SelectFolder">Select Fo_lder</Button>
<Button Name="OpenBoth">Select _Both</Button>
</StackPanel>
</Expander>
<Expander Header="Launcher dialogs">
<StackPanel Spacing="4">

95
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -1,23 +1,14 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
#pragma warning disable CS0618 // Type or member is obsolete
#nullable enable
namespace ControlCatalog.Pages
{
@ -70,14 +61,6 @@ namespace ControlCatalog.Pages
};
List<FileDialogFilter> GetFilters()
{
return GetFileTypes()?.Select(f => new FileDialogFilter
{
Name = f.Name, Extensions = f.Patterns!.ToList()
}).ToList() ?? new List<FileDialogFilter>();
}
List<FilePickerFileType>? BuildFileTypes()
{
var selectedItem = (FilterSelector.SelectedItem as ComboBoxItem)?.Content
@ -168,88 +151,12 @@ namespace ControlCatalog.Pages
void UpdateSuggestedFilterSelectorState() =>
suggestedFilterSelector.IsEnabled = useSuggestedFilter.IsChecked == true;
useSuggestedFilter.Checked += (_, _) => UpdateSuggestedFilterSelectorState();
useSuggestedFilter.Unchecked += (_, _) => UpdateSuggestedFilterSelectorState();
useSuggestedFilter.IsCheckedChanged += (_, _) => UpdateSuggestedFilterSelectorState();
UpdateSuggestedFilterSelectorState();
FilterSelector.SelectionChanged += (_, _) => UpdateSuggestedFilterSelector(BuildFileTypes());
UpdateSuggestedFilterSelector(BuildFileTypes());
OpenFile.Click += async delegate
{
// Almost guaranteed to exist
var uri = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName;
var initialFileName = uri == null ? null : System.IO.Path.GetFileName(uri);
var initialDirectory = uri == null ? null : System.IO.Path.GetDirectoryName(uri);
var result = await new OpenFileDialog()
{
Title = "Open file",
Filters = GetFilters(),
Directory = initialDirectory,
InitialFileName = initialFileName
}.ShowAsync(GetWindow());
results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true;
};
OpenMultipleFiles.Click += async delegate
{
var result = await new OpenFileDialog()
{
Title = "Open multiple files",
Filters = GetFilters(),
Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null,
AllowMultiple = true
}.ShowAsync(GetWindow());
results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true;
};
SaveFile.Click += async delegate
{
var filters = GetFilters();
var result = await new SaveFileDialog()
{
Title = "Save file",
Filters = filters,
Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null,
DefaultExtension = filters?.Any() == true ? "txt" : null,
InitialFileName = "test.txt"
}.ShowAsync(GetWindow());
results.ItemsSource = new[] { result };
resultsVisible.IsVisible = result != null;
};
SelectFolder.Click += async delegate
{
var result = await new OpenFolderDialog()
{
Title = "Select folder",
Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null,
}.ShowAsync(GetWindow());
if (string.IsNullOrEmpty(result))
{
resultsVisible.IsVisible = false;
}
else
{
SetFolder(await GetStorageProvider().TryGetFolderFromPathAsync(result!));
results.ItemsSource = new[] { result };
resultsVisible.IsVisible = true;
}
};
OpenBoth.Click += async delegate
{
var result = await new OpenFileDialog()
{
Title = "Select both",
Directory = lastSelectedDirectory?.Path is {IsAbsoluteUri:true} path ? path.LocalPath : null,
AllowMultiple = true
}.ShowManagedAsync(GetWindow(), new ManagedFileDialogOptions
{
AllowDirectorySelection = true
});
results.ItemsSource = result;
resultsVisible.IsVisible = result?.Any() == true;
};
DecoratedWindow.Click += delegate
{
new DecoratedWindow().Show();

25
src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs

@ -1,25 +0,0 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Avalonia.Metadata;
namespace Avalonia.Controls.Platform
{
/// <summary>
/// Defines a platform-specific system dialog implementation.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
[Unstable]
public interface ISystemDialogImpl
{
/// <summary>
/// Shows a file dialog.
/// </summary>
/// <param name="dialog">The details of the file dialog to show.</param>
/// <param name="parent">The parent window.</param>
/// <returns>A task returning the selected filenames.</returns>
Task<string[]?> ShowFileDialogAsync(FileDialog dialog, Window parent);
Task<string?> ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent);
}
}

70
src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs

@ -1,70 +0,0 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
namespace Avalonia.Controls.Platform
{
/// <summary>
/// Defines a platform-specific system dialog implementation.
/// </summary>
[Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
internal class SystemDialogImpl : ISystemDialogImpl
{
public async Task<string[]?> ShowFileDialogAsync(FileDialog dialog, Window parent)
{
if (dialog is OpenFileDialog openDialog)
{
var filePicker = parent.StorageProvider;
if (!filePicker.CanOpen)
{
return null;
}
var options = openDialog.ToFilePickerOpenOptions();
var files = await filePicker.OpenFilePickerAsync(options);
return files
.Select(file => file.TryGetLocalPath() ?? file.Name)
.ToArray();
}
else if (dialog is SaveFileDialog saveDialog)
{
var filePicker = parent.StorageProvider;
if (!filePicker.CanSave)
{
return null;
}
var options = saveDialog.ToFilePickerSaveOptions();
var file = await filePicker.SaveFilePickerAsync(options);
if (file is null)
{
return null;
}
var filePath = file.TryGetLocalPath() ?? file.Name;
return new[] { filePath };
}
return null;
}
public async Task<string?> ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent)
{
var filePicker = parent.StorageProvider;
if (!filePicker.CanPickFolder)
{
return null;
}
var options = dialog.ToFolderPickerOpenOptions();
var folders = await filePicker.OpenFolderPickerAsync(options);
return folders
.Select(folder => folder.TryGetLocalPath() ?? folder.Name)
.FirstOrDefault(u => u is not null);
}
}
}

206
src/Avalonia.Controls/SystemDialog.cs

@ -1,206 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Platform;
using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO;
namespace Avalonia.Controls
{
/// <summary>
/// Base class for system file dialogs.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class FileDialog : FileSystemDialog
{
/// <summary>
/// Gets or sets a collection of filters which determine the types of files displayed in an
/// <see cref="OpenFileDialog"/> or an <see cref="SaveFileDialog"/>.
/// </summary>
public List<FileDialogFilter> Filters { get; set; } = new List<FileDialogFilter>();
/// <summary>
/// Gets or sets initial file name that is displayed when the dialog is opened.
/// </summary>
public string? InitialFileName { get; set; }
}
/// <summary>
/// Base class for system file and directory dialogs.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class FileSystemDialog : SystemDialog
{
/// <summary>
/// Gets or sets the initial directory that will be displayed when the file system dialog
/// is opened.
/// </summary>
public string? Directory { get; set; }
}
/// <summary>
/// Represents a system dialog that prompts the user to select a location for saving a file.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class SaveFileDialog : FileDialog
{
/// <summary>
/// Gets or sets the default extension to be used to save the file (including the period ".").
/// </summary>
public string? DefaultExtension { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to display a warning if the user specifies the name of a file that already exists.
/// </summary>
public bool? ShowOverwritePrompt { get; set; }
/// <summary>
/// Shows the save file dialog.
/// </summary>
/// <param name="parent">The parent window.</param>
/// <returns>
/// A task that on completion contains the full path of the save location, or null if the
/// dialog was canceled.
/// </returns>
public async Task<string?> ShowAsync(Window parent)
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return (await service.ShowFileDialogAsync(this, parent) ??
Array.Empty<string>()).FirstOrDefault();
}
public FilePickerSaveOptions ToFilePickerSaveOptions()
{
return new FilePickerSaveOptions
{
SuggestedFileName = InitialFileName,
DefaultExtension = DefaultExtension,
FileTypeChoices = Filters?.Select(f => new FilePickerFileType(f.Name!) { Patterns = f.Extensions.Select(e => $"*.{e}").ToArray() }).ToArray(),
Title = Title,
SuggestedStartLocation = Directory is { } directory
? new BclStorageFolder(new System.IO.DirectoryInfo(directory))
: null,
ShowOverwritePrompt = ShowOverwritePrompt
};
}
}
/// <summary>
/// Represents a system dialog that allows the user to select one or more files to open.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class OpenFileDialog : FileDialog
{
/// <summary>
/// Gets or sets a value indicating whether the user can select multiple files.
/// </summary>
public bool AllowMultiple { get; set; }
/// <summary>
/// Shows the open file dialog.
/// </summary>
/// <param name="parent">The parent window.</param>
/// <returns>
/// A task that on completion returns an array containing the full path to the selected
/// files, or null if the dialog was canceled.
/// </returns>
public Task<string[]?> ShowAsync(Window parent)
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return service.ShowFileDialogAsync(this, parent);
}
public FilePickerOpenOptions ToFilePickerOpenOptions()
{
return new FilePickerOpenOptions
{
AllowMultiple = AllowMultiple,
FileTypeFilter = Filters?.Select(f => new FilePickerFileType(f.Name!) { Patterns = f.Extensions.Select(e => $"*.{e}").ToArray() }).ToArray(),
Title = Title,
SuggestedStartLocation = Directory is { } directory
? new BclStorageFolder(new System.IO.DirectoryInfo(directory))
: null
};
}
}
/// <summary>
/// Represents a system dialog that allows the user to select a directory.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class OpenFolderDialog : FileSystemDialog
{
/// <summary>
/// Shows the open folder dialog.
/// </summary>
/// <param name="parent">The parent window.</param>
/// <returns>
/// A task that on completion returns the full path of the selected directory, or null if the
/// dialog was canceled.
/// </returns>
public Task<string?> ShowAsync(Window parent)
{
if(parent == null)
throw new ArgumentNullException(nameof(parent));
var service = AvaloniaLocator.Current.GetRequiredService<ISystemDialogImpl>();
return service.ShowFolderDialogAsync(this, parent);
}
public FolderPickerOpenOptions ToFolderPickerOpenOptions()
{
return new FolderPickerOpenOptions
{
Title = Title,
SuggestedStartLocation = Directory is { } directory
? new BclStorageFolder(new System.IO.DirectoryInfo(directory))
: null
};
}
}
/// <summary>
/// Base class for system dialogs.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class SystemDialog
{
static SystemDialog()
{
if (AvaloniaLocator.Current.GetService<ISystemDialogImpl>() is null)
{
// Register default implementation.
AvaloniaLocator.CurrentMutable.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogImpl>();
}
}
/// <summary>
/// Gets or sets the dialog title.
/// </summary>
public string? Title { get; set; }
}
/// <summary>
/// Represents a filter in an <see cref="OpenFileDialog"/> or an <see cref="SaveFileDialog"/>.
/// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class FileDialogFilter
{
/// <summary>
/// Gets or sets the name of the filter, e.g. ("Text files (.txt)").
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Gets or sets a list of file extensions matched by the filter (e.g. "txt" or "*" for all
/// files).
/// </summary>
public List<string> Extensions { get; set; } = new List<string>();
}
}

20
src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs

@ -1,11 +1,7 @@
using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Controls.Primitives;
using Avalonia.Platform.Storage;
namespace Avalonia.Dialogs
@ -41,22 +37,6 @@ namespace Avalonia.Dialogs
return builder.UseManagedSystemDialogs(() => new TWindow());
}
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public static Task<string[]> ShowManagedAsync(this OpenFileDialog dialog, Window parent,
ManagedFileDialogOptions? options = null) => ShowManagedAsync<Window>(dialog, parent, options);
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public static async Task<string[]> ShowManagedAsync<TWindow>(this OpenFileDialog dialog, Window parent,
ManagedFileDialogOptions? options = null) where TWindow : Window, new()
{
var impl = new ManagedStorageProvider(parent, PrepareOptions(options, () => new TWindow()));
var files = await impl.OpenFilePickerAsync(dialog.ToFilePickerOpenOptions());
return files
.Select(file => file.TryGetLocalPath() ?? file.Name)
.ToArray();
}
private static ManagedFileDialogOptions? PrepareOptions(
ManagedFileDialogOptions? optionsOverride = null,
Func<ContentControl>? customRootFactory = null)

Loading…
Cancel
Save