Я использую 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>
Кто-нибудь понимает, почему у меня такое странное поведение?
Также укажите в сообщении версию .NET и платформу, которую вы использовали. Невозможно воспроизвести вашу проблему на основе вашего кода.
@LiqunShen-MSFT Я ориентируюсь только на Windows10 с .NET 8.0.
@MustafaMutasim К сожалению, это не сработало. Могу я спросить, какова причина этого?
Поскольку это работает Glyph = "{x:Static helpers:IconFont.Add}", это означает, что существует проблема с привязкой
Это странно. Я почти использую ваш код, и он работает на моей стороне («он покажет +»). Отображает ли кнопка правильный текст?
@LiqunShen-MSFT Да, так и есть. Я также посмотрел, правильно ли передается глиф, что не составило проблем.
@MustafaMutasim Но как происходит сбой привязки?
Каков текущий статус? решено?
как происходит сбой привязки? Причин много, но в данном случае я думаю, что FontImageSource должен быть привязан к верхнему слою.
@user25033240 user25033240 Я действительно не могу это воспроизвести. Вы можете опубликовать дополнительный код, чтобы помочь нам воспроизвести этот вопрос. Или это произойдет, если вы создадите новый проект только с приведенным выше кодом в вашем вопросе?
Я почти использую тот же код, что и ваш.
@LiqunShen-MSFT В новом проекте проблема не возникает.
@MustafaMutasim Однако приведенное выше предложение не работает в новом проекте. Есть ли альтернативный подход к использованию относительной привязки, о котором я не знаю?
@MustafaMutasim Ваша привязка Glyph = "{Binding Source = {RelativeSource AncestorType = {x:Type Button}}, Path=ButtonGlyph}" работает в моем примере проекта, когда я заменяю AncestorType на {x:Type ButtonObject}.
@ user25033240 Ну, поскольку новый проект работает, возможно, эту проблему вызывают другие части проекта. Было бы лучше, если бы вы разместили более соответствующий код, который поможет нам найти основную причину.
@LiqunShen-MSFT Возникла еще одна проблема, более срочная/блокирующая этот поток. Я отчитаюсь, как только смогу. Спасибо за активную помощь и понимание!

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