123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- using System;
- using System.Buffers;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- 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
- {
- public class DialogsPage : UserControl
- {
- public DialogsPage()
- {
- this.InitializeComponent();
- IStorageFolder? lastSelectedDirectory = null;
- bool ignoreTextChanged = false;
- var results = this.Get<ItemsControl>("PickerLastResults");
- var resultsVisible = this.Get<TextBlock>("PickerLastResultsVisible");
- var bookmarkContainer = this.Get<TextBox>("BookmarkContainer");
- var openedFileContent = this.Get<TextBox>("OpenedFileContent");
- var openMultiple = this.Get<CheckBox>("OpenMultiple");
- var currentFolderBox = this.Get<AutoCompleteBox>("CurrentFolderBox");
- currentFolderBox.TextChanged += async (sender, args) =>
- {
- if (ignoreTextChanged) return;
- if (Enum.TryParse<WellKnownFolder>(currentFolderBox.Text, true, out var folderEnum))
- {
- lastSelectedDirectory = await GetStorageProvider().TryGetWellKnownFolderAsync(folderEnum);
- }
- else
- {
- if (!Uri.TryCreate(currentFolderBox.Text, UriKind.Absolute, out var folderLink))
- {
- Uri.TryCreate("file://" + currentFolderBox.Text, UriKind.Absolute, out folderLink);
- }
- if (folderLink is not null)
- {
- lastSelectedDirectory = await GetStorageProvider().TryGetFolderFromPathAsync(folderLink);
- }
- }
- };
- List<FileDialogFilter> GetFilters()
- {
- if (this.Get<CheckBox>("UseFilters").IsChecked != true)
- return new List<FileDialogFilter>();
- return new List<FileDialogFilter>
- {
- new FileDialogFilter
- {
- Name = "Text files (.txt)", Extensions = new List<string> {"txt"}
- },
- new FileDialogFilter
- {
- Name = "All files",
- Extensions = new List<string> {"*"}
- }
- };
- }
- List<FilePickerFileType>? GetFileTypes()
- {
- if (this.Get<CheckBox>("UseFilters").IsChecked != true)
- return null;
- return new List<FilePickerFileType>
- {
- FilePickerFileTypes.All,
- FilePickerFileTypes.TextPlain,
- new("Binary Log")
- {
- Patterns = new[] { "*.binlog", "*.buildlog" },
- MimeTypes = new[] { "application/binlog", "application/buildlog" },
- AppleUniformTypeIdentifiers = new []{ "public.data" }
- }
- };
- }
- this.Get<Button>("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;
- };
- this.Get<Button>("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;
- };
- this.Get<Button>("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;
- };
- this.Get<Button>("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;
- }
- };
- this.Get<Button>("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;
- };
- this.Get<Button>("DecoratedWindow").Click += delegate
- {
- new DecoratedWindow().Show();
- };
- this.Get<Button>("DecoratedWindowDialog").Click += delegate
- {
- _ = new DecoratedWindow().ShowDialog(GetWindow());
- };
- this.Get<Button>("Dialog").Click += delegate
- {
- var window = CreateSampleWindow();
- window.Height = 200;
- _ = window.ShowDialog(GetWindow());
- };
- this.Get<Button>("DialogNoTaskbar").Click += delegate
- {
- var window = CreateSampleWindow();
- window.Height = 200;
- window.ShowInTaskbar = false;
- _ = window.ShowDialog(GetWindow());
- };
- this.Get<Button>("OwnedWindow").Click += delegate
- {
- var window = CreateSampleWindow();
- window.Show(GetWindow());
- };
- this.Get<Button>("OwnedWindowNoTaskbar").Click += delegate
- {
- var window = CreateSampleWindow();
- window.ShowInTaskbar = false;
- window.Show(GetWindow());
- };
- this.Get<Button>("OpenFilePicker").Click += async delegate
- {
- var result = await GetStorageProvider().OpenFilePickerAsync(new FilePickerOpenOptions()
- {
- Title = "Open file",
- FileTypeFilter = GetFileTypes(),
- SuggestedStartLocation = lastSelectedDirectory,
- AllowMultiple = openMultiple.IsChecked == true
- });
- await SetPickerResult(result);
- };
- this.Get<Button>("SaveFilePicker").Click += async delegate
- {
- var fileTypes = GetFileTypes();
- var file = await GetStorageProvider().SaveFilePickerAsync(new FilePickerSaveOptions()
- {
- Title = "Save file",
- FileTypeChoices = fileTypes,
- SuggestedStartLocation = lastSelectedDirectory,
- SuggestedFileName = "FileName",
- DefaultExtension = fileTypes?.Any() == true ? "txt" : null,
- ShowOverwritePrompt = false
- });
- if (file is not null)
- {
- // Sync disposal of StreamWriter is not supported on WASM
- #if NET6_0_OR_GREATER
- await using var stream = await file.OpenWriteAsync();
- await using var reader = new System.IO.StreamWriter(stream);
- #else
- using var stream = await file.OpenWriteAsync();
- using var reader = new System.IO.StreamWriter(stream);
- #endif
- await reader.WriteLineAsync(openedFileContent.Text);
- SetFolder(await file.GetParentAsync());
- }
- await SetPickerResult(file is null ? null : new[] { file });
- };
- this.Get<Button>("OpenFolderPicker").Click += async delegate
- {
- var folders = await GetStorageProvider().OpenFolderPickerAsync(new FolderPickerOpenOptions()
- {
- Title = "Folder file",
- SuggestedStartLocation = lastSelectedDirectory,
- AllowMultiple = openMultiple.IsChecked == true
- });
- await SetPickerResult(folders);
- SetFolder(folders.FirstOrDefault());
- };
- this.Get<Button>("OpenFileFromBookmark").Click += async delegate
- {
- var file = bookmarkContainer.Text is not null
- ? await GetStorageProvider().OpenFileBookmarkAsync(bookmarkContainer.Text)
- : null;
- await SetPickerResult(file is null ? null : new[] { file });
- };
- this.Get<Button>("OpenFolderFromBookmark").Click += async delegate
- {
- var folder = bookmarkContainer.Text is not null
- ? await GetStorageProvider().OpenFolderBookmarkAsync(bookmarkContainer.Text)
- : null;
- await SetPickerResult(folder is null ? null : new[] { folder });
- SetFolder(folder);
- };
- void SetFolder(IStorageFolder? folder)
- {
- ignoreTextChanged = true;
- lastSelectedDirectory = folder;
- currentFolderBox.Text = folder?.Path is { IsAbsoluteUri: true } abs ? abs.LocalPath : folder?.Path?.ToString();
- ignoreTextChanged = false;
- }
- async Task SetPickerResult(IReadOnlyCollection<IStorageItem>? items)
- {
- items ??= Array.Empty<IStorageItem>();
- bookmarkContainer.Text = items.FirstOrDefault(f => f.CanBookmark) is { } f ? await f.SaveBookmarkAsync() : "Can't bookmark";
- var mappedResults = new List<string>();
- if (items.FirstOrDefault() is IStorageItem item)
- {
- var resultText = item is IStorageFile ? "File:" : "Folder:";
- resultText += Environment.NewLine;
- var props = await item.GetBasicPropertiesAsync();
- resultText += @$"Size: {props.Size}
- DateCreated: {props.DateCreated}
- DateModified: {props.DateModified}
- CanBookmark: {item.CanBookmark}
- ";
- if (item is IStorageFile file)
- {
- resultText += @$"
- Content:
- ";
- resultText += await ReadTextFromFile(file, 10000);
- }
- openedFileContent.Text = resultText;
- var parent = await item.GetParentAsync();
- SetFolder(parent);
- if (parent is not null)
- {
- mappedResults.Add(FullPathOrName(parent));
- }
- foreach (var selectedItem in items)
- {
- mappedResults.Add("+> " + FullPathOrName(selectedItem));
- if (selectedItem is IStorageFolder folder)
- {
- foreach (var innerItems in await folder.GetItemsAsync())
- {
- mappedResults.Add("++> " + FullPathOrName(innerItems));
- }
- }
- }
- }
- results.ItemsSource = mappedResults;
- resultsVisible.IsVisible = mappedResults.Any();
- }
- }
- public static async Task<string> ReadTextFromFile(IStorageFile file, int length)
- {
- #if NET6_0_OR_GREATER
- await using var stream = await file.OpenReadAsync();
- #else
- using var stream = await file.OpenReadAsync();
- #endif
- using var reader = new System.IO.StreamReader(stream);
- // 4GB file test, shouldn't load more than 10000 chars into a memory.
- var buffer = ArrayPool<char>.Shared.Rent(length);
- try
- {
- var charsRead = await reader.ReadAsync(buffer, 0, length);
- return new string(buffer, 0, charsRead);
- }
- finally
- {
- ArrayPool<char>.Shared.Return(buffer);
- }
- }
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnAttachedToVisualTree(e);
- var openedFileContent = this.Get<TextBox>("OpenedFileContent");
- try
- {
- var storageProvider = GetStorageProvider();
- openedFileContent.Text = $@"CanOpen: {storageProvider.CanOpen}
- CanSave: {storageProvider.CanSave}
- CanPickFolder: {storageProvider.CanPickFolder}";
- }
- catch (Exception ex)
- {
- openedFileContent.Text = "Storage provider is not available: " + ex.Message;
- }
- }
- private Window CreateSampleWindow()
- {
- Button button;
- Button dialogButton;
- var window = new Window
- {
- Height = 200,
- Width = 200,
- Content = new StackPanel
- {
- Spacing = 4,
- Children =
- {
- new TextBlock { Text = "Hello world!" },
- (button = new Button
- {
- HorizontalAlignment = HorizontalAlignment.Center,
- Content = "Click to close",
- IsDefault = true
- }),
- (dialogButton = new Button
- {
- HorizontalAlignment = HorizontalAlignment.Center,
- Content = "Dialog",
- IsDefault = false
- })
- }
- },
- WindowStartupLocation = WindowStartupLocation.CenterOwner
- };
- button.Click += (_, __) => window.Close();
- dialogButton.Click += (_, __) =>
- {
- var dialog = CreateSampleWindow();
- dialog.Height = 200;
- dialog.ShowDialog(window);
- };
- return window;
- }
- private IStorageProvider GetStorageProvider()
- {
- var forceManaged = this.Get<CheckBox>("ForceManaged").IsChecked ?? false;
- return forceManaged
- ? new ManagedStorageProvider<Window>(GetWindow(), null)
- : GetTopLevel().StorageProvider;
- }
- private static string FullPathOrName(IStorageItem? item)
- {
- if (item is null) return "(null)";
- return item.Path is { IsAbsoluteUri: true } path ? path.ToString() : item.Name;
- }
- Window GetWindow() => TopLevel.GetTopLevel(this) as Window ?? throw new NullReferenceException("Invalid Owner");
- TopLevel GetTopLevel() => TopLevel.GetTopLevel(this) ?? throw new NullReferenceException("Invalid Owner");
- private void InitializeComponent()
- {
- AvaloniaXamlLoader.Load(this);
- }
- }
- }
- #pragma warning restore CS0618 // Type or member is obsolete
|