ListView не отображает привязку ObservableProperty из ViewModel

Я новичок в .NET MAUI/MVVM/SQLite и C#, если уж на то пошло. Я пытаюсь использовать свою ViewModel для привязки данных из моего класса модели. Я могу прекрасно использовать пространство имен модели в качестве свойства привязки, и оно отображает данные в моем списке. Однако как только я пытаюсь использовать свою ViewModel, она больше не отображается.

CRUDView XAML работает

        <Frame Grid.Row = "6" Grid.Column = "1" Grid.ColumnSpan = "3" BackgroundColor = "#B1C0C9" BorderColor = "#7989A3">
            <ScrollView Orientation = "Vertical">
                <ListView x:Name = "listView" 
                          BackgroundColor = "Gray" 
                          HasUnevenRows = "True"
                          SeparatorVisibility = "Default"
                          ItemTapped = "listView_ItemTapped"
                          FlexLayout.Grow = "1"
                          >
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <VerticalStackLayout Padding = "5">
                                    <Label Text = "{Binding Question}"
                                           FontSize = "17" 
                                           FontFamily = "OCRA" 
                                           TextColor = "Black"/>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width = "50"/>
                                            <ColumnDefinition Width = "*"/>
                                            <ColumnDefinition Width = "*"/>
                                            <ColumnDefinition Width = "Auto"/>
                                        </Grid.ColumnDefinitions>
                                        <Label Text = "{Binding Id}"
                                               FontSize = "10" 
                                               FontFamily = "OCRA" 
                                               TextColor = "Black"
                                               Grid.Column = "0"
                                               />
                                        <Label Text = "{Binding Answer}"
                                               FontSize = "15" 
                                               FontFamily = "OCRA" 
                                               TextColor = "White"
                                               Grid.Column = "1"
                                               Padding = "10"/>
                                        <Label Text = "{Binding Difficulty}"
                                               FontSize = "15" 
                                               FontFamily = "OCRA" 
                                               TextColor = "Black"
                                               Grid.Column = "3"
                                               Padding = "10"/>
                                    </Grid>
                                    
                                </VerticalStackLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </ScrollView>

        </Frame>

Отображение данных в ListView

Когда я вернусь к использованию ViewModel для привязки данных:

CRUDView XAML

<Frame Grid.Row = "6" Grid.Column = "1" Grid.ColumnSpan = "3" BackgroundColor = "#B1C0C9" BorderColor = "#7989A3">
    <ScrollView Orientation = "Vertical">
        <ListView x:Name = "listView" 
                  BackgroundColor = "Gray" 
                  HasUnevenRows = "True"
                  SeparatorVisibility = "Default"
                  ItemTapped = "listView_ItemTapped"
                  FlexLayout.Grow = "1"
                  ItemsSource = "{Binding Flashcards}">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType = "vm:CRUDViewModel">
                    <ViewCell>
                        <VerticalStackLayout Padding = "5">
                            <Label Text = "{Binding Flashcard.Question}"
                                   FontSize = "17" 
                                   FontFamily = "OCRA" 
                                   TextColor = "Black"/>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width = "50"/>
                                    <ColumnDefinition Width = "*"/>
                                    <ColumnDefinition Width = "*"/>
                                    <ColumnDefinition Width = "Auto"/>
                                </Grid.ColumnDefinitions>
                                <Label Text = "{Binding Flashcard.Id}"
                                       FontSize = "10" 
                                       FontFamily = "OCRA" 
                                       TextColor = "Black"
                                       Grid.Column = "0"
                                       />
                                <Label Text = "{Binding Flashcard.Answer}"
                                       FontSize = "15" 
                                       FontFamily = "OCRA" 
                                       TextColor = "White"
                                       Grid.Column = "1"
                                       Padding = "10"/>
                                <Label Text = "{Binding Flashcard.Difficulty}"
                                       FontSize = "15" 
                                       FontFamily = "OCRA" 
                                       TextColor = "Black"
                                       Grid.Column = "3"
                                       Padding = "10"/>
                            </Grid>
                            
                        </VerticalStackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ScrollView>

</Frame>

Модель представления

namespace cadflash.ViewModels
{
    public partial class CRUDViewModel : ObservableObject
    {
        [ObservableProperty]
        public ObservableCollection<Flashcard> flashcards = new();

        [ObservableProperty]
        public Flashcard flashcard = new();
        
        public CRUDViewModel()
        {
            Flashcard = new Flashcard();
            Flashcards = [];
        }

МауиПрограмма

MauiProgram

    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("OCRAEXT.ttf", "OCRA");
                });

            builder.Services.AddSingleton<LocalDbService>();
            builder.Services.AddTransient<HomeView>();
            builder.Services.AddTransient<DifficultyView>();
            builder.Services.AddTransient<CRUDView>();
            builder.Services.AddTransient<CRUDViewModel>();
            builder.Services.AddTransient<DifficultyViewModel>();
            builder.Services.AddTransient<HomeViewModel>();


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

            return builder.Build();
        }
    }
}

CRUDView.cs

CRUDView.xaml.cs

public partial class CRUDView : ContentPage
{
    CRUDViewModel viewModel;
    private readonly LocalDbService localDbService; // This is the service that is used to interact with the local database
    private int _editFlashcardId; // This is the ID of the flashcard that is being edited
    public CRUDView(LocalDbService localDbService)
    {
        InitializeComponent();
        BindingContext = new CRUDViewModel();
        this.localDbService = localDbService;
        Task.Run(async () => await localDbService.GetFlashcardsAsync());
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();
        listView.ItemsSource = await localDbService.GetFlashcardsAsync();
    }

В ListView нет данных

Это была неделя мучительной боли в попытках отобразить данные в списке. Сегодня я придумал, как просто привязать данные непосредственно из класса модели. В идеале я хотел бы использовать привязку ViewModel...

во-первых, вы назначаете ItemsSource как в XAML, так и в коде. Выбирайте одно или другое, а не оба. Во-вторых, в вашей виртуальной машине вы инициализируете FlashCards в пустой список и никогда не добавляете в него какие-либо данные.

Jason 07.04.2024 03:45

@Jason Что мне нужно сделать на виртуальной машине, чтобы инициализировать список Flashcard для уже заполненной базы данных SQLite?

Brett Simonds 07.04.2024 03:52

что-то вроде Flashcards = await localDbService.GetFlashcardsAsync();

Jason 07.04.2024 03:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Есть некоторые проблемы с использованием в вашем коде.

Во-первых, поскольку вы пытались использовать MVVM, вам необходимо добавить соответствующий код localDbService в вашу модель MVVM. Например, вы можете добавить в модель MVVM метод localDbService и загрузку данных.

    //private readonly LocalDbService localDbService; // This is the service that is used to interact with the local database

    public CRUDViewModel()
    {
        //initialize localDbService and load data
        //this.localDbService = localDbService;
    }

Во-вторых, поскольку вы установили ItemsSource = "{Binding Flashcards}" для своего ListView, тип данных DataTemplate ListView должен быть Flashcard, а не <DataTemplate x:DataType = "vm:CRUDViewModel">.

В-третьих, удалите префикс Flashcard при привязке (например, <Label Text = "{Binding Flashcard.Id}").

Я достиг этой функции с некоторыми поддельными данными.

Вы можете обратиться к следующему коду:

CRUDViewModel.cs

public partial class CRUDViewModel:ObservableObject
{
    [ObservableProperty]
    public ObservableCollection<Flashcard> flashcards = new();

    [ObservableProperty]
    public Flashcard flashcard = new();


    //private readonly LocalDbService localDbService; // This is the service that is used to interact with the local database


    public CRUDViewModel()
    {
        Flashcard = new Flashcard();
        Flashcards = [];

        //initialize localDbService and load data
        //this.localDbService = localDbService;
       
        GetData();
    }

    public async void GetData() {

        //List<Flashcard>  datas = await localDbService.GetFlashcardsAsync());

        // add the data to Flashcards
        //foreach (Flashcard flashcard in datas) {
        //    Flashcards.Add(flashcard);
        //}

        //add some fake data to variable Flashcards
        Flashcards.Add(new Flashcard { Id = 01, Question = "1+ 1 = ", Answer = "2", Difficulty = "easy" });
        Flashcards.Add(new Flashcard { Id = 02, Question = "1+ 3 = ", Answer = "4", Difficulty = "easy" });
        Flashcards.Add(new Flashcard { Id = 03, Question = "123+163 = ", Answer = "286", Difficulty = "difficult" });

    }
}

MainPage.xaml

<?xml version = "1.0" encoding = "utf-8" ?>
<ContentPage xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
             
             xmlns:models = "clr-namespace:MauiMvvmListApp0407.Models"
             x:Class = "MauiMvvmListApp0407.MainPage">

    <Frame Grid.Row = "6"  Grid.Column = "1" Grid.ColumnSpan = "3" BackgroundColor = "#B1C0C9" BorderColor = "#7989A3">
            <ListView x:Name = "listView"
                  BackgroundColor = "Gray"
                  HasUnevenRows = "True"
                  SeparatorVisibility = "Default"
                  ItemsSource = "{Binding Flashcards}">
                <ListView.ItemTemplate>
                <DataTemplate x:DataType = "models:Flashcard">
                        <ViewCell>
                            <VerticalStackLayout Padding = "5">
                                <Label Text = "{Binding Question}"
                                   FontSize = "17"
                                   FontFamily = "OCRA"
                                   TextColor = "Black"/>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width = "50"/>
                                        <ColumnDefinition Width = "*"/>
                                        <ColumnDefinition Width = "*"/>
                                        <ColumnDefinition Width = "Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Text = "{Binding Id}"
                                       FontSize = "10"
                                       FontFamily = "OCRA"
                                       TextColor = "Black"
                                       Grid.Column = "0"
                                       />
                                    <Label Text = "{Binding Answer}"
                                       FontSize = "15"
                                       FontFamily = "OCRA"
                                       TextColor = "White"
                                       Grid.Column = "1"
                                       Padding = "10"/>
                                    <Label Text = "{Binding Difficulty}"
                                       FontSize = "15"
                                       FontFamily = "OCRA"
                                       TextColor = "Black"
                                       Grid.Column = "3"
                                       Padding = "10"/>
                                </Grid>

                            </VerticalStackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
    </Frame>
</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    CRUDViewModel viewModel;
    public MainPage()
    {
        InitializeComponent();

        viewModel = new CRUDViewModel();
        this.BindingContext = viewModel;
    }
}

Большое спасибо! Изменение DataTemplate на model:Flashcard решило проблему. Я также воспользовался вашим советом и включил другие предложенные изменения.

Brett Simonds 07.04.2024 14:30

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