Редактирование копий объекта ObservableCollection без редактирования ObservableCollection - PullRequest
0 голосов
/ 06 мая 2020

У меня есть форма WPF, которую я хочу использовать для управления таблицей базы данных. Чтобы получить данные из базы данных, я использую Entity Framework Core. Я пытаюсь следовать шаблону MVVM.

Итак, у меня есть модель под названием «Сотрудник» с рядом строковых свойств, таких как имя и т. Д. В форме есть ListView, который показывает ObservableCollection сотрудника. Кроме того, у меня есть несколько текстовых полей для отображения и управления свойствами отдельных объектов Employee. SelectedMemberPath ListView привязан к свойству SelectedEmployee. Установщик SelectedEmployee копирует собственные свойства в EditedEmployee. Текстовые поля привязаны к EditedEmployee. Идея в том, что я не хочу напрямую редактировать ObservableCollection. Это должно происходить только при нажатии кнопки сохранения.

Это моя модель представления.

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using XdcCore.Models;
using XdcCore.ViewModels.Commands;

namespace XdcCore.ViewModels
{
    class EmployeeEditorVM : List<Employee>, INotifyPropertyChanged
    {
        public EmployeeSaveCommand EmployeeSaveCommand { get; set; }

        public EmployeeEditorVM()
        {
            EmployeeSearch();

            EmployeeSaveCommand = new EmployeeSaveCommand(this);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private string employeeSearchText;

        public string EmployeeSearchText
        {
            get { return employeeSearchText; }
            set
            {
                employeeSearchText = value;
                OnPropertyChanged("EmployeeSearch");
                EmployeeSearch();
            }
        }

        private Employee selectedEmployee;

        public Employee SelectedEmployee
        {
            get { return selectedEmployee; }
            set
            {
                selectedEmployee = value;
                OnPropertyChanged("SelectedEmployee");
                EditedEmployee = SelectedEmployee;
            }
        }

        private Employee editedEmployee;

        public Employee EditedEmployee
        {
            get { return editedEmployee; }
            set
            {
                editedEmployee = value;
                OnPropertyChanged("EditedEmployee");
            }
        }

        private ObservableCollection<Employee> employees;

        public ObservableCollection<Employee> Employees
        {
            get { return employees; }
            set
            {
                employees = value;
                OnPropertyChanged("Employees");
            }
        }

        public void EmployeeSearch()
        {
            using (var context = new XdcContext())
            {
                if (employeeSearchText != null)
                {
                    var _employees = context.Employee
                        .Where(x => x.Firstname.Contains(employeeSearchText));
                    Employees = new ObservableCollection<Employee>(_employees);
                }
                else
                {
                    var _employees = context.Employee.Select(x => x);
                    Employees = new ObservableCollection<Employee>(_employees);
                }
            }
        }

        public void EmployeeSave()
        {
            using (var context = new XdcContext())
            {
                var entity = context.Employee.First(x => x.IdEmployee == SelectedEmployee.IdEmployee);
                {
                    entity.Firstname = SelectedEmployee.Firstname;
                    entity.Lastname = SelectedEmployee.Lastname;
                    entity.Initials = SelectedEmployee.Initials;

                    context.SaveChanges();
                }
                EmployeeSearch();
            }
        }
    }
}

это мое представление:

<Window
    x:Class="XdcCore.Views.Editors.EmployeeEditor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:XdcCore.Views.Editors"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:XdcCore.ViewModels"
    Title="Employee"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Window.Resources>
        <vm:EmployeeEditorVM x:Key="vm" />
    </Window.Resources>
    <Grid DataContext="{StaticResource vm}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="300" />
                <ColumnDefinition Width="115*" />
                <ColumnDefinition Width="277*" />
            </Grid.ColumnDefinitions>

            <!--  left column  -->
            <Border BorderBrush="DarkGray" BorderThickness="1">
                <Grid Grid.Column="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="aUTO" />
                    </Grid.RowDefinitions>
                    <Label
                        Grid.Row="0"
                        Margin="3,3,3,3"
                        Content="Filter:" />
                    <TextBox
                        x:Name="TextBoxSearch"
                        Grid.Row="1"
                        Height="25"
                        Margin="3,0,3,3"
                        HorizontalContentAlignment="Left"
                        VerticalContentAlignment="Center"
                        Text="{Binding EmployeeSearchText, Mode=TwoWay}" />
                    <ListView
                        x:Name="ListViewOverview"
                        Grid.Row="2"
                        Margin="3,0,3,0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        ItemsSource="{Binding Employees, Mode=OneWay}"
                        SelectedItem="{Binding SelectedEmployee, Mode=OneWayToSource}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Initials}" />
                                    <TextBlock Text=" : " />
                                    <TextBlock Text="{Binding Firstname}" />
                                    <TextBlock Text=" " />
                                    <TextBlock Text="{Binding Lastname}" />
                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                    <Grid Grid.Row="3">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>

                        <Button
                            x:Name="ButtonDelete"
                            Grid.Column="0"
                            Height="25"
                            Margin="3,3,3,3"
                            Content="Delete"
                            IsEnabled="False" />
                        <Button
                            x:Name="ButtonNew"
                            Grid.Column="1"
                            Height="25"
                            Margin="3,3,3,3"
                            Content="Add New ..."
                            IsEnabled="True" />
                    </Grid>
                </Grid>
            </Border>

            <!--  right Column  -->
            <Grid Grid.Column="1" Grid.ColumnSpan="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>


                <!--  right column, first row  -->
                <Border
                    Grid.Row="0"
                    BorderBrush="DarkGray"
                    BorderThickness="1">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="25" />
                            <RowDefinition Height="25" />
                            <RowDefinition Height="25" />
                            <RowDefinition Height="25" />
                            <RowDefinition Height="25" />
                            <RowDefinition Height="25" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="200" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Label
                            Grid.Row="0"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            Content="First Name" />
                        <Label
                            Grid.Row="1"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            Content="Last Name" />
                        <Label
                            Grid.Row="2"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            Content="Initials" />
                        <Label
                            Grid.Row="3"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            VerticalContentAlignment="Center"
                            Content="ID" />
                        <Label
                            Grid.Row="4"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            VerticalContentAlignment="Center"
                            Content="RCU" />
                        <Label
                            Grid.Row="5"
                            Grid.Column="0"
                            HorizontalAlignment="Right"
                            VerticalContentAlignment="Center"
                            Content="RCT" />
                        <TextBox
                            x:Name="TextBoxFirstName"
                            Grid.Row="0"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            Text="{Binding EditedEmployee.Firstname, Mode=TwoWay}" />
                        <TextBox
                            x:Name="TextBoxLastName"
                            Grid.Row="1"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            Text="{Binding EditedEmployee.Lastname, Mode=TwoWay}" />
                        <TextBox
                            x:Name="TextBoxInitials"
                            Grid.Row="2"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            Text="{Binding EditedEmployee.Initials, Mode=TwoWay}" />
                        <TextBox
                            x:Name="TextBoxId"
                            Grid.Row="3"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            IsReadOnly="True" />
                        <TextBox
                            x:Name="TextBoxRCU"
                            Grid.Row="4"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            IsReadOnly="True" />
                        <TextBox
                            x:Name="TextBoxRCT"
                            Grid.Row="5"
                            Grid.Column="1"
                            Margin="0,3,3,3"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            HorizontalContentAlignment="Left"
                            VerticalContentAlignment="Center"
                            IsReadOnly="True" />

                    </Grid>
                </Border>
                <Grid Grid.Row="1">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>

                    <Button
                        x:Name="ButnSave"
                        Grid.Column="1"
                        Width="76"
                        Height="25"
                        Margin="60,3,60,0"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Top"
                        Command="{Binding EmployeeSaveCommand}"
                        Content="Save"
                        IsEnabled="True" />
                </Grid>
                <!--  Add new  -->

            </Grid>
        </Grid>
    </Grid>
</Window>

Другими словами: Я хочу щелкнуть элемент в представлении списка, сведения о нем отображаются в текстовых полях. Я могу изменить текст в текстовых полях, но изменения не применяются к наблюдаемой коллекции (или даже к базе данных), пока я не нажму «сохранить». Проблема в том, что именно это и происходит: когда я редактирую текст в текстовых полях, изменения также отображаются в виде списка. И я не понимаю почему.

1 Ответ

0 голосов
/ 07 мая 2020

Итак, я неправильно понял концепцию «копирование против точки» переменной.

У меня было два решения моей проблемы.

  1. К моей модели сотрудников я добавил Метод Копировать:
    public partial class Employee
    {
        public int IdEmployee { get; set; }
        public string Initials { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public string Rcu { get; set; }
        public DateTime Rct { get; set; }

        public Employee Copy()
        {
            return (Employee)this.MemberwiseClone();
        }
    }

Затем я изменил свою ViewModel так, чтобы EditedEmployee был копией SelectedEmployee

        private Employee selectedEmployee;

        public Employee SelectedEmployee
        {
            get { return selectedEmployee; }
            set
            {
                selectedEmployee = value;
                OnPropertyChanged("SelectedEmployee");
                if (SelectedEmployee != null)
                {
                    EditedEmployee = SelectedEmployee.Copy();
                }
            }
        }

        private Employee editedEmployee;

        public Employee EditedEmployee
        {
            get { return editedEmployee; }
            set
            {
                editedEmployee = value;
                OnPropertyChanged("EditedEmployee");
            }
        }

Проблема с этим подходом заключается в том, что если я возьмусь с базу данных, а затем снова нужно запустить Scaffold-DbContext (я предпочитаю кодовый подход EF C), мне пришлось бы снова изменить все модели. Решением этого может быть какая-то вторая модифицированная модель, которая наследуется от исходной модели и затем добавляет метод копирования.

Мой второй подход - привязать ListView через SelectedIndex вместо SelectedItem.

<ListView
...
ItemsSource="{Binding Employees, Mode=OneWay}"
SelectedIndex="{Binding SelectedItemIndex, Mode=TwoWay}">

Затем в ViewModel это представлено свойством int. Если это int установлено (и> = 0), сотрудник будет скопирован EmployeeWorkingCopy. Кроме того, если EmployeeWorkingCopy установлен, один Сотрудник с именем EditedEmployee устанавливается как Сотрудник рабочей копии с выбранным индексом.

private int selectedItemIndex;

public int SelectedItemIndex
{
  get { return selectedItemIndex; }
  set
  {
  selectedItemIndex = value;
  if (SelectedItemIndex >= 0)
  EmployeesWorkingCopy = new ObservableCollection<Employee>(Employees);
  }
}

private Employee editedEmployee;

public Employee EditedEmployee
{
 get { return editedEmployee; }
 set
 {
 editedEmployee = value;
 OnPropertyChanged("EditedEmployee");
 }
}

private ObservableCollection<Employee> employeesWorkingCopy;

public ObservableCollection<Employee> EmployeesWorkingCopy
{
get { return employeesWorkingCopy; }
set
 {
    employeesWorkingCopy = value;
    EditedEmployee = EmployeesWorkingCopy[SelectedItemIndex];
  }
}

Большое спасибо за указание на мое заблуждение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...