Кнопка .NET MAUI, динамически добавленная в CollectionView, не отображает Glyph/ImageSource

Я использую CollectionView в .NET MAUI, чтобы динамически добавлять кнопки и, следовательно, иметь возможность динамически изменять порядок кнопок.

Для этого я создал модель ButtonObject:

public class ButtonObject
{
    public string? ButtonText { get; set; }
    public IRelayCommand? ButtonCommand { get; set; }
    public bool? ButtonIsVisible { get; set; }
    public string? ButtonGlyph { get; set; }

}

Эта модель используется для создания кнопок в ViewModel:

    public partial class TestViewModel
    {
        [ObservableProperty]
        private ObservableCollection<ButtonObject> _buttons = new();
 
        private ButtonObject _testButton;

        [ObservableProperty]
        private string _testGlyph = IconFont.Add;

        public TestViewModel()
        {
            _testButton = new ButtonObject()
            {
                ButtonText = "Title",
                ButtonCommand = PerformActionCommand,
                ButtonIsVisible = true,
                ButtonGlyph = TestGlyph,
            };

            _buttons.Add(_testButton);
        }

        [RelayCommand]
        private void OnPerformAction()
        {
            //...
        }
    }

Представление использует CollectionView для отображения кнопок:

<CollectionView ItemsSource = "{Binding Buttons}"
                ItemsLayout = "HorizontalList"
                SelectionMode = "None"
                ItemSizingStrategy = "MeasureFirstItem">
<CollectionView.ItemTemplate>
    <DataTemplate>
        <Grid Padding = "20">
            <Button MaximumWidthRequest = "150"
                    x:DataType = "models:ButtonObject"
                    Text = "{x:Binding ButtonText}"
                    Command = "{x:Binding ButtonCommand}"
                    IsVisible = "{x:Binding ButtonIsVisible}">
                <Button.ImageSource>
                    <FontImageSource FontFamily = "MSO"
                                     Glyph = "{x:Binding ButtonGlyph}"
                                     Size = "20" />
                </Button.ImageSource>
            </Button>
        </Grid>
    </DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

Однако глиф не отображается в CollectionView.

По поводу значка: ViewModel извлекает информацию об значке из отдельного класса:

public static class IconFont
{
    public const string Add = "\ue145";
    // many more...
}

А FontFamily взят из Material Icons от Google:

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .UseMauiCommunityToolkit()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                    fonts.AddFont("MaterialIcons-Regular.ttf", "MaterialIconsRegular");
                    fonts.AddFont("MaterialSymbolsOutlined.ttf", "MSO"); // MSO = Material Symbols Outlined
                })
                .ConfigureEssentials(essentials =>
                {
                    essentials.UseVersionTracking();
                });

#if DEBUG
            builder.Logging.AddDebug();
#endif

            return builder.Build();
        }
    }
}

Я попытался использовать класс IconFont напрямую, и это сработало:

<ContentPage xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class = "Project.Views.TestView"
             xmlns:helpers = "clr-namespace:Project.Helpers"
             xmlns:mct = "http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:toolkit = "http://schemas.microsoft.com/dotnet/2022/maui/toolkit">

<!-- ... -->

<CollectionView ItemsSource = "{Binding Buttons}"
                ItemsLayout = "HorizontalList"
                SelectionMode = "None"
                ItemSizingStrategy = "MeasureFirstItem">
<CollectionView.ItemTemplate>
    <DataTemplate>
        <Grid Padding = "20">
            <Button MaximumWidthRequest = "150"
                    x:DataType = "models:ButtonObject"
                    Text = "{x:Binding ButtonText}"
                    Command = "{x:Binding ButtonCommand}"
                    IsVisible = "{x:Binding ButtonIsVisible}">
                <Button.ImageSource>
                    <FontImageSource FontFamily = "MSO"
                                     Glyph = "{x:Static helpers:IconFont.Add}"
                                     Size = "20" />
                </Button.ImageSource>
            </Button>
        </Grid>
    </DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

</ContentPage>

Кто-нибудь понимает, почему у меня такое странное поведение?

Replace Glyph = "{x:Binding ButtonGlyph}" with Glyph = "{Binding Source = {RelativeSource AncestorType = {x:Type Button}}, Path=ButtonGlyph}
Mustafa Mutasim 12.06.2024 14:26

Также укажите в сообщении версию .NET и платформу, которую вы использовали. Невозможно воспроизвести вашу проблему на основе вашего кода.

Liqun Shen-MSFT 13.06.2024 08:10

@LiqunShen-MSFT Я ориентируюсь только на Windows10 с .NET 8.0.

user25033240 13.06.2024 11:08

@MustafaMutasim К сожалению, это не сработало. Могу я спросить, какова причина этого?

user25033240 13.06.2024 11:09

Поскольку это работает Glyph = "{x:Static helpers:IconFont.Add}", это означает, что существует проблема с привязкой

Mustafa Mutasim 13.06.2024 11:17

Это странно. Я почти использую ваш код, и он работает на моей стороне («он покажет +»). Отображает ли кнопка правильный текст?

Liqun Shen-MSFT 13.06.2024 11:25

@LiqunShen-MSFT Да, так и есть. Я также посмотрел, правильно ли передается глиф, что не составило проблем.

user25033240 13.06.2024 12:02

@MustafaMutasim Но как происходит сбой привязки?

user25033240 13.06.2024 12:02

Каков текущий статус? решено?

Mustafa Mutasim 13.06.2024 14:18

как происходит сбой привязки? Причин много, но в данном случае я думаю, что FontImageSource должен быть привязан к верхнему слою.

Mustafa Mutasim 13.06.2024 14:29

@user25033240 user25033240 Я действительно не могу это воспроизвести. Вы можете опубликовать дополнительный код, чтобы помочь нам воспроизвести этот вопрос. Или это произойдет, если вы создадите новый проект только с приведенным выше кодом в вашем вопросе?

Liqun Shen-MSFT 14.06.2024 07:53

Я почти использую тот же код, что и ваш.

Liqun Shen-MSFT 14.06.2024 10:45

@LiqunShen-MSFT В новом проекте проблема не возникает.

user25033240 17.06.2024 07:02

@MustafaMutasim Однако приведенное выше предложение не работает в новом проекте. Есть ли альтернативный подход к использованию относительной привязки, о котором я не знаю?

user25033240 17.06.2024 07:03

@MustafaMutasim Ваша привязка Glyph = "{Binding Source = {RelativeSource AncestorType = {x:Type Button}}, Path=ButtonGlyph}" работает в моем примере проекта, когда я заменяю AncestorType на {x:Type ButtonObject}.

user25033240 17.06.2024 07:16

@ user25033240 Ну, поскольку новый проект работает, возможно, эту проблему вызывают другие части проекта. Было бы лучше, если бы вы разместили более соответствующий код, который поможет нам найти основную причину.

Liqun Shen-MSFT 17.06.2024 07:36

@LiqunShen-MSFT Возникла еще одна проблема, более срочная/блокирующая этот поток. Я отчитаюсь, как только смогу. Спасибо за активную помощь и понимание!

user25033240 17.06.2024 09:10
5 дизайнов темных кнопок с использованием HTML и CSS
5 дизайнов темных кнопок с использованием HTML и CSS
Здесь представлены пять дизайнов темных кнопок с кодом с использованием HTML и CSS:
1
17
113
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Использование привязки Glyph = "{Binding Source = {RelativeSource AncestorType = {x:Type ButtonObject}}, Path=ButtonGlyph}" работает! Спасибо @MustafaMutasim

Другие вопросы по теме