简体   繁体   中英

C# Data doesn't appear in ComboBox although the list is not empty

Good time of day, I ran into a problem. I have a ComboBox to enter data from the database. I can take data from the database, but for some reason the data doesn't want to be displayed in the ComboBox. What do I need to do to display the data? Thank you in advance.

BoatView.xaml :

<UserControl x:Class="OrderBoatNew.WPF.Controls.BoatCard"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:OrderBoatNew.WPF.Controls"
             xmlns:vm="clr-namespace:OrderBoatNew.WPF.ViewModels"
             mc:Ignorable="d"
             d:DesignHeight="400" d:DesignWidth="400">

    <UserControl.DataContext>
        <vm:BoatCardViewModel />
    </UserControl.DataContext>

    <Grid>
        <StackPanel Orientation="Horizontal">

            <Grid Margin="15 15 0 0">

                <Grid.Resources>
                    <Style TargetType="ComboBox">
                        <Setter Property="Margin"
                                Value="0 20 0 0" />
                    </Style>
                </Grid.Resources>

                <Grid.RowDefinitions>
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="auto" />
                </Grid.RowDefinitions>

                <TextBlock Text="Model:"
                           Grid.Row="0" />
                <ComboBox Grid.Row="0"
                          Width="150"
                          ItemsSource="{Binding Models}"
                          DisplayMemberPath="Name" />

                <TextBlock Text="Wood:"
                           Grid.Row="1" />
                <ComboBox Grid.Row="1"
                          ItemsSource="{Binding Woods}" />

                <TextBlock Text="Color:"
                           Grid.Row="2" />
                <ComboBox Grid.Row="2"
                          ItemsSource="{Binding Colors}" />
            </Grid>
        </StackPanel>
    </Grid>
</UserControl>

I tried to take both the table and immediately take the Name from the table, but not one of these options doesn't work.

BoatCardViewModel.cs

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using OrderBoatNew.Domain.Models;
using OrderBoatNew.Domain.Services;
using OrderBoatNew.EntityFramework.Services;
using OrderBoatNew.EntityFramework;

namespace OrderBoatNew.WPF.ViewModels
{
    public class BoatViewModel : ViewModelBase
    {
        private readonly IDataService<Model> _modelService;
        private readonly IDataService<Wood> _woodService;
        private readonly IDataService<Color> _colorService;

        private List<Model> _models;

        public List<Model> Models
        {
            get => _models;
            set
            {
                _models = value;
                OnPropertyChanged(nameof(Models));
            }
        }
        
        private List<string> _woods;

        public List<string> Woods
        {
            get => _woods;
            set
            {
                _woods = value;
                OnPropertyChanged(nameof(Woods));
            }
        }

        private List<string> _colors;

        public List<string> Colors
        {
            get => _colors;
            set
            {
                _colors = value;
                OnPropertyChanged(nameof(Colors));
            }
        }

        public BoatViewModel()
        {
            var contextFactory = new OrderBoatNewDbContextFactory();
            _modelService = new GenericDataService<Model>(contextFactory);
            _woodService = new GenericDataService<Wood>(contextFactory);
            _colorService = new GenericDataService<Color>(contextFactory);
        }

        public static BoatViewModel LoadBoatViewModel()
        {
            BoatViewModel boatViewModel = new BoatViewModel();
            boatViewModel.LoadValues();

            return boatViewModel;
        }

        private async void LoadValues()
        {
            await _modelService.GetAll().ContinueWith(task =>
            {
                if (task.Exception == null)
                    Models = task.Result.ToList();
            });

            await _woodService.GetAll().ContinueWith(task =>
            {
                if (task.Exception == null)
                    Woods = task.Result.Select(w => w.Name).ToList();
            });

            await _colorService.GetAll().ContinueWith(task =>
            {
                if (task.Exception == null)
                    Colors = task.Result.Where(c => c.ForAdditionalMoney == false)
                                        .Select(c => c.Name)
                                        .ToList();
            });
        }
    }
}

IDataService.cs

using System.Collections.Generic;
using System.Threading.Tasks;

namespace OrderBoatNew.Domain.Services
{
    public interface IDataService<T>
    {
        Task<IEnumerable<T>> GetAll();
        Task<T> Get(int id);
        Task<T> Create(T entity);
        Task<T> Update(int id, T entity);
        Task<bool> Delete(int id);
    }
}

GenericDataService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using OrderBoatNew.Domain.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using OrderBoatNew.Domain.Models;

namespace OrderBoatNew.EntityFramework.Services
{
    public class GenericDataService<T> : IDataService<T> where T : DomainObject
    {
        private readonly OrderBoatNewDbContextFactory _contextFactory;

        public GenericDataService(OrderBoatNewDbContextFactory contextFactory) { _contextFactory = contextFactory; }

        public async Task<IEnumerable<T>> GetAll()
        {
            using (OrderBoatNewDbContext context = _contextFactory.CreateDbContext())
            {
                IEnumerable<T> entities = await context.Set<T>().ToListAsync();

                return entities;
            }
        }

        public async Task<T> Get(int id)
        {
            using (OrderBoatNewDbContext context = _contextFactory.CreateDbContext())
            {
                T entity = await context.Set<T>().FirstOrDefaultAsync((e) => e.ID == id);

                return entity;
            }
        }

        public async Task<T> Create(T entity)
        {
            using (OrderBoatNewDbContext context = _contextFactory.CreateDbContext())
            {
                EntityEntry<T> createdResult = await context.Set<T>().AddAsync(entity);
                await context.SaveChangesAsync();

                return createdResult.Entity;
            }
        }

        public async Task<T> Update(int id, T entity)
        {
            using (OrderBoatNewDbContext context = _contextFactory.CreateDbContext())
            {
                entity.ID = id;

                context.Set<T>().Update(entity);
                await context.SaveChangesAsync();

                return entity;
            }
        }

        public async Task<bool> Delete(int id)
        {
            using (OrderBoatNewDbContext context = _contextFactory.CreateDbContext())
            {
                T entity = await context.Set<T>().FirstOrDefaultAsync((e) => e.ID == id);
                context.Set<T>().Remove(entity);
                await context.SaveChangesAsync();

                return true;
            }
        }
    }
}

UpdateViewModelCommand.cs

#nullable enable

using System;
using System.Windows.Input;
using OrderBoatNew.Domain.Models;
using OrderBoatNew.EntityFramework.Services;
using OrderBoatNew.WPF.Services;
using OrderBoatNew.WPF.State.Navigators;
using OrderBoatNew.WPF.ViewModels;

namespace OrderBoatNew.WPF.Commands
{
    public class UpdateViewModelCommand : ICommand
    {
        private readonly INavigator _navigator;

        public UpdateViewModelCommand(INavigator navigator)
        {
            _navigator = navigator;
        }

        public bool CanExecute(object? parameter)
        {
            return true;
        }

        public void Execute(object? parameter)
        {
            if (parameter is ViewType viewType)
            {
                _navigator.CurrentViewModel = viewType switch
                {
                    ViewType.Boats => BoatViewModel.LoadBoatViewModel(),
                    ViewType.BoatsAccessory => new BoatAccessoryViewModel(),
                    _ => throw new ArgumentOutOfRangeException()
                };
            }
        }

        public event EventHandler? CanExecuteChanged;
    }
}

First of all, you assign an instance of a BoatCardViewModel as DataContext .

<UserControl.DataContext>
   <vm:BoatCardViewModel />
</UserControl.DataContext>

You should never do that, this breaks data context inheritance. You should either bind the data context property where the user control is actually used if needed, eg:

<BoatCard DataContext="{Binding ...}" />

Now, the problem is that the data context view model is created using the parameterless constructor, which initializes the services, but never calls them to get the data.

Another issue is that the LoadBoatViewModel method either does not get called at all or it is useless, as a call returns a new instance of a BoatCardViewModel which is never set in your user control. Therefore, you are potentially using two different instances of the view model, without noticing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM