ObservableCollection не обновляется => DataGrid UI не показывает все - PullRequest
1 голос
/ 07 июня 2019

У меня проблема с кодом, который я написал. Я пытаюсь создать программу «Заявитель-администрация». У меня есть SQL-сервер, на котором находится моя база данных.

В начале программы DataGrid привязывается к ObservableCollection который запускает SQL SELECT через Dapper.

Если я вставляю нового кандидата с другим запросом SQL, DataGrid не показывает этого нового кандидата.

Я отлаживал свою программу, чтобы увидеть, что происходит не так. Я думаю, что это ObservableCollection, к которому я привязываюсь.

Код DataGrid

<DataGrid x:Name="DgInformation" ItemsSource="{Binding AllData,Mode=TwoWay}"
                  SelectedItem="{Binding SelectedApplicantModel, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
                  AutoGenerateColumns="False"
                  Grid.Row="2"
                  MaxHeight="870"
                  IsSynchronizedWithCurrentItem="True"
                  IsReadOnly="True"
                  CanUserAddRows="False"
                  CanUserDeleteRows="False"
                  HorizontalAlignment="Center"
                  Margin="10,5,10,5"
                  Background="#F5F5F5"
                  AlternatingRowBackground="#eeeeee" AlternationCount="2">
            <DataGrid.RowStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <EventSetter Event="MouseDoubleClick" Handler="DG_Information_MouseDoubleClick" />
                    <EventSetter Event="KeyDown" Handler="DG_Information_KeyDown" />
                </Style>
            </DataGrid.RowStyle>
            <DataGrid.Columns>
                <materialDesign:MaterialDataGridTextColumn Header="Vorname" Width="110"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding FirstName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Nachname" Width="110"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding LastName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Geburtstag" Width="110"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Birthday,Mode=TwoWay, StringFormat=\{0:dd.MM.yy\}, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Schulabschluss" Width="140"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Graduation.Graduation,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="PLZ" Width="90"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding PostCode,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Ort"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Address.HomePlace, Mode =TwoWay,UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Geschlecht"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Gender.Gender,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <DataGridHyperlinkColumn Header="E-Mail"
                                         EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                         Binding="{Binding EMail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                    <DataGridHyperlinkColumn.ElementStyle>
                        <Style>
                            <EventSetter Event="Hyperlink.Click" Handler="DgHyperlinkClick" />
                        </Style>
                    </DataGridHyperlinkColumn.ElementStyle>
                </DataGridHyperlinkColumn>
                <materialDesign:MaterialDataGridTextColumn Header="Stelle"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Job,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <materialDesign:MaterialDataGridTextColumn Header="Bewertung"
                                                           EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
                                                           Binding="{Binding Grade.Grade, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            </DataGrid.Columns>
        </DataGrid>

Моя ViewModel

public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private ObservableCollection<ApplicantModel> _allData;

        public BaseViewModel()
        {
            AllData = ApplicantService.GetInstance().GetAll();
        }

        public ObservableCollection<ApplicantModel> AllData
        {
            get { return _allData; }
            set
            {
                _allData = value;
                OnPropertyChanged();
            }
        }

Мой класс обслуживания

private readonly IApplicantRepository _repository;

        public ApplicantService()
        {
            _repository = new ApplicantRepository();
        }

        public ObservableCollection<ApplicantModel> GetAll()
        {
            return _repository.GetAll();
        }

И мой репозиторий

public ObservableCollection<ApplicantModel> GetAll()
        {
                var result =
                    Db.Query<ApplicantModel, AddressModel, GraduationModel, GenderModel, GradeModel, ApplicantModel>(
                        "SELECT a.ID, a.FirstName, a.LastName, a.Birthday, a.EMail, a.Job, ad.PostCode, ad.HomePlace, g.Graduation, g.ID, ge.Gender, ge.ID, Grade.Grade FROM dbo.Applicant As a INNER JOIN Address As ad ON ad.PostCode = a.PostCode INNER JOIN Graduation As g ON g.ID = a.GraduationID INNER JOIN Gender As ge On ge.ID = a.GenderID INNER JOIN Grade ON Grade.Grade = a.GradeID",
                        _mapSelectGetAll, splitOn: "HomePlace,Graduation,Gender,Grade");
                Logger.LogInfo("Function GetAll executed in ApplicantRepository!");

                ObservableCollection<ApplicantModel> obsCollection = new ObservableCollection<ApplicantModel>(result);
                return obsCollection;
        }

        private ApplicantModel _mapSelectGetAll(ApplicantModel applicant, AddressModel address, GraduationModel graduation, GenderModel gender, GradeModel grade)
        {
            applicant.Graduation = graduation;
            applicant.Address = address;
            applicant.Gender = gender;
            applicant.Grade = grade;

            return applicant;
        }

Я надеюсь, что кто-нибудь может показать мне, где ошибка.

Ответы [ 2 ]

0 голосов
/ 11 июня 2019

@ Icepickle

Мой запрос на вставку:

public void CreateApplicant(ApplicantModel applicant, AddressModel address, GraduationModel graduation, GenderModel gender, GradeModel grade)
        {
            string query = "INSERT INTO Applicant(FirstName,LastName,PostCode,Birthday,GenderID,Email,Job,GraduationID,GradeID)" + "Values(@FirstName,@LastName,@PostCode,@Birthday,@Gender,@Email,@Job,@Graduation,@Grade)";

            try
            {
                Db.Execute(query, new
                {
                    FirstName = applicant.FirstName,
                    LastName = applicant.LastName,
                    Birthday = applicant.Birthday,
                    PostCode = applicant.PostCode,
                    Graduation = graduation.ID,
                    Gender = gender.ID,
                    Email = applicant.EMail,
                    Job = applicant.Job,
                    Grade = grade.Grade,
                });
                Logger.LogInfo("Function AddApplicant executed in ApplicantRepository!");
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }

И различные детали заполняются в текстовые поля, которые привязаны к свойствам моей базы данных

0 голосов
/ 07 июня 2019

Ваш анализ точен :) Это действительно проблема с вашей привязкой к AllData, главным образом потому, что вы позволяете переназначить ее в установщике.

Ваш DataGrid действительно только слушает изменения вашего ObservableCollection (точнее, обрабатывает интерфейс INotifyCollectionChanged. Он не знает, что ваш родительский объект изменил саму коллекцию (даже если вы запускаете PropertyChanged событие)

В идеале вы должны автоматически инициализировать наблюдаемые коллекции и не разрешать какие-либо внешние настройки. Пусть он обрабатывает добавление / удаление / сброс через CollectionChanged.

Хорошо, что теперь вы можете написать свою программу более простым способом (не нужно проходить мимо ObservableCollection<T>)

Таким образом, ваше свойство viewmodel будет иметь следующий вид:

public IList<ApplicantModel> AllData { get; } = new ObservableCollection<ApplicationModel>();

, поскольку ObservableCollection<T> наследуется от IList<T>, нет проблем с его обобщением. DataGrid все равно обнаружит интерфейс INotifyCollectionChanged.

Это, однако, означает, что вы больше не можете назначать новую коллекцию свойству, но это, по сути, хорошая вещь :) Кроме того, свойство AllData никогда не будет нулевым, так что это еще одна хорошая вещь.

Однако теперь вам нужно переписать логику обновления вашего свойства AllData на вашем ViewModel

Итак, если вы все еще хотите автоматически заполнить его в конструкторе, вы можете изменить свойство и конструктор viewmodel на:

public BaseViewModel() {
    AllData = new ObservableCollection<ApplicantModel>( ApplicantService.GetInstance().GetAll() );
} 

public IList<ApplicantModel> AllData { get; }

И нет необходимости в частном вспомогательном поле, теперь у вас есть авто-свойство только для чтения, и конструктор использует параметр конструктора IEnumerable<T> для ObservableCollection<T>

Затем вы должны изменить свой класс обслуживания, для этого нет особой причины возвращать полностью взорванный ObservableCollection<ApplicantModel>(), просто дайте ему вернуть IEnumerable<ApplicantModel> или самое большее IReadOnlyList<ApplicantModel>.

Это изменение также необходимо перейти к вашему Repository.

Это, в конечном счете, оставляет вас в распоряжении для удаления и обновления данных. Если вы работаете с какой-то локальной базой данных, то при работе с запросами на сохранение / удаление было бы хорошо, если вы работаете с центральной базой данных, это может быть более сложным:)

Надеюсь, это не слишком много текста:)

...