Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set Title for OpenFolderDialog in an Avalonia application?

I'm working with OpenFileDialog, SaveFileDialog and OpenFolderDialog in an Avalonia application.
One requirement is to set the title to a certain string.
I achieved this for OpenFileDialog and SaveFileDialog but not for OpenFolderDialog.
OpenFolderDialog resists applying the title, so that only a default title according the language of the operating system remains set.

I found that in ControlCatalogStandalone the OpenFolderDialog works correct, i.e. the title can be set as desired.
So, I tried to reduce ControlCatalogStandalone to the Dialogs functionality and transform it to be as similar as possible to my test application.
I couldn't achieve that, but I found some clue that might help a more skilled developer to find the reason for the misbehavior of my test application.

The Solution and the Projects of ControlCatalogStandalone are structured and composed much different to my Avalonia test application.
In my test application the target framework is .NET Core 3.1.
In one Project of the ControlCatalogStandalone Solution the target framework is .NET Standard 2.0.
So, I think OpenFolderDialog works correct in .NET Standard but not in .NET Core.
I also think that if ControlCatalogStandalone was built from scratch with the current version of the Avalonia for Visual Studio Extension, it wouldn't produce a mix of frameworks.

Here are the relevant code parts of my test application:

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);
        }
    }
}

I'm showing the last file because I wasn't able to implement the method Window GetWindow() => (Window)this.VisualRoot; in my ViewModel which in ControlCatalogStandalone is implemented and used in the code behind of DialogsPage (which actually is a UserControl).
So, I implemented the Instance property which perhaps is a hack.
If you also could give me hint on best practice to get the instance of the MainWindow I'd be happy.

Is my problem not being able to set the title in OpenFolderDialog an open issue of the .NET Core implementation, or can you tell me how to get it working in my simple test application?

like image 203
Zoldan Avatar asked Nov 07 '22 05:11

Zoldan


1 Answers

I'm not familiar/experienced with the Avalon framework so I won't comment too much on your different setup tests. However it seems that the OpenFolderDialog has a bug that it doesn't set the title when being showed, atleast for its Windows implementation. This is reported as a issue on the github source, and seems not yet solved:

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

(In comparison to here for FileDialog). Reference: https://github.com/AvaloniaUI/Avalonia/issues/3037

Without further digging into the source, its unclear why the ControlCatalogStandalone example functions correctly since it appears to use the same method in #ShowAsync (used here), which is defined here.

like image 76
Ben Avatar answered Nov 15 '22 05:11

Ben