如何在 Avalonia 应用程序中设置 OpenFolderDialog 的标题?

How to set Title for OpenFolderDialog in an Avalonia application?

我正在 Avalonia 应用程序中使用 OpenFileDialogSaveFileDialogOpenFolderDialog
一个要求是将标题设置为某个字符串。
我为 OpenFileDialogSaveFileDialog 实现了这一点,但 而不是 OpenFolderDialog.
OpenFolderDialog 拒绝应用标题,因此仅保留根据操作系统语言设置的默认标题。

我发现在 ControlCatalogStandaloneOpenFolderDialog 工作正常,即标题可以根据需要设置。
因此,我尝试将 ControlCatalogStandalone 减少为 Dialogs 功能,并将其转换为尽可能与我的测试应用程序相似。
我无法做到这一点,但我发现了一些线索,可以帮助更熟练的开发人员找到我的测试应用程序行为不当的原因。

ControlCatalogStandaloneSolutionProject 的结构和组成与我的 Avalonia 测试应用程序有很大不同。
在我的测试应用程序中,目标框架是 .NET Core 3.1.
ControlCatalogStandalone 解决方案的一个项目中,目标框架是 .NET Standard 2.0.
所以,我认为 OpenFolderDialog.NET Standard 中工作正确,但在 .NET Core.
中不正确 我还认为,如果 ControlCatalogStandalone 是使用 Avalonia for Visual Studio 扩展的当前版本从头开始构建的,它不会产生框架的混合。

以下是我的测试应用程序的相关代码部分:

MainWindow.axaml:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:DialogTests.ViewModels;assembly=DialogTests"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" Width="200" Height="150"
        x:Class="DialogTests.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="DialogTests">

    <Design.DataContext>
        <vm:MainWindowViewModel/>
    </Design.DataContext>

    <Grid RowDefinitions="*,*,*">
        <Button Grid.Column="0" Grid.Row="0" Command="{Binding OpenFileDialogCommand}" Content="OpenFileDialog"/>
        <Button Grid.Column="0" Grid.Row="1" Command="{Binding SaveFileDialogCommand}" Content="SaveFileDialog"/>
        <Button Grid.Column="0" Grid.Row="2" Command="{Binding OpenFolderDialogCommand}" Content="OpenFolderDialog"/>
    </Grid>

</Window>

MainWindowViewModel.cs:

using Avalonia.Controls;
using DialogTests.Views;
using ReactiveUI;
using System.Collections.Generic;
using System.Reactive;

namespace DialogTests.ViewModels
{
    public class MainWindowViewModel : ViewModelBase
    {
        public MainWindowViewModel()
        {
            OpenFileDialogCommand = ReactiveCommand.Create(() => {
                new OpenFileDialog()
                {
                    Title = "Open File Dialog",
                    Filters = GetFilters()
                }.ShowAsync(MainWindow.Instance);
            });

            SaveFileDialogCommand = ReactiveCommand.Create(() =>
            {
                new SaveFileDialog()
                {
                    Title = "Save File Dialog",
                    Filters = GetFilters()
                }.ShowAsync(MainWindow.Instance);
            });

            OpenFolderDialogCommand = ReactiveCommand.Create(() => {
                new OpenFolderDialog()
                {
                    Title = "Open Folder Dialog"
                }.ShowAsync(MainWindow.Instance);
            });
        }

        public ReactiveCommand<Unit, Unit> OpenFileDialogCommand { get; }
        public ReactiveCommand<Unit, Unit> SaveFileDialogCommand { get; }
        public ReactiveCommand<Unit, Unit> OpenFolderDialogCommand { get; }

        List<FileDialogFilter> GetFilters()
        {
            return new List<FileDialogFilter>
                {
                    new FileDialogFilter
                    {
                        Name = "Text files", Extensions = new List<string> {"txt"}
                    },
                    new FileDialogFilter
                    {
                        Name = "All files",
                        Extensions = new List<string> {"*"}
                    }
                };
        }
    }
}

MainWindow.axaml.cs:

using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;

namespace DialogTests.Views
{
    public class MainWindow : Window
    {
        public static MainWindow Instance { get; private set; }
        public MainWindow()
        {
            Instance = this;
            InitializeComponent();
#if DEBUG
            this.AttachDevTools();
#endif
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }
    }
}

我正在显示最后一个文件,因为我无法实现该方法 Window GetWindow() => (Window)this.VisualRoot; 在我的 ViewModel 中,在 ControlCatalogStandalone 中实现并用于 DialogsPage 的代码(实际上是 UserControl)。
所以,我实现了 Instance 属性 这可能是一个 hack。
如果您还可以给我提示有关获取 MainWindow 实例的最佳实践,我会很高兴。

我无法在 OpenFolderDialog 中设置标题的问题是 .NET Core 实现的未解决问题,还是您能告诉我如何让它在我的简单测试应用程序中工作?

我 familiar/experienced 不熟悉 Avalon 框架,所以我不会对您的不同设置测试发表太多评论。然而,OpenFolderDialog 似乎有一个错误,它在显示时没有设置标题,至少对于它的 Windows 实现。这是 github 来源上的一个问题,似乎尚未解决:

frm.SetTitle is missing for the folder dialog: Windows/Avalonia.Win32/SystemDialogImpl#L116

(与 FileDialog 的 here 相比)。 参考:https://github.com/AvaloniaUI/Avalonia/issues/3037

在不进一步深入研究源代码的情况下,不清楚为什么 ControlCatalogStandalone 示例可以正常运行,因为它似乎在 #ShowAsync 中使用了相同的方法(使用 here), which is defined here.