Как прочитать все значения текстового поля (сопоставить с файлами базы данных) и сохранить их в базе данных в WPF — MVVM

#wpf #mvvm #data-binding

#wpf #mvvm #привязка к данным

Вопрос:

Я новичок в WPF и MVVM. После долгого изобретения я узнал, как извлекать данные из базы данных и привязывать их к itemcontrol / listview / gridview.

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

Вот мой пример кода..

Вид

 <ItemsControl ItemsSource="{Binding AllEmployees}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBox Width="100" Text="{Binding FirstName}" Margin="4"/>
                        <TextBox Width="100" Text="{Binding LastName}" Margin="4"/>
                        <TextBox Width="100" Text="{Binding Age}" Margin="4"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
</ItemsControl>
<!-- For new Employee Details -->
<StackPanel>
        <TextBox x:Name="FirstName"/>
        <TextBox x:Name="LastName"/>
        <TextBox x:Name="Age"/>
        <Button Content="New" Command="{Binding NewEmployeeCommand}"/>
 </StackPanel>
  

Мой cs-файл

     public ObservableCollection<DataAccess.Employee> AllEmployees
            {
                get;
                private set;
            }  

    public EmployeeListViewModel(EmployeeRepository employeeRepository)
            {
                if (employeeRepository == null)
                {
                    throw new ArgumentNullException("employeeRepository");
                }

                _employeeRepository = employeeRepository;
                this.AllEmployees = new ObservableCollection<DataAccess.Employee> 
                                    (_employeeRepository.ListAll());
 }  
  

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

Как написать функцию для события NewEmployeeCommand для чтения текстовых полей (сопоставления текстовых полей с соответствующими файлами данных в базе данных) и сохранения данных в базе данных.

Большое спасибо!

Ответ №1:

если вы пытаетесь использовать MVVM, просто необходимо:

  • Создайте свою ViewModel, чтобы содержать все свойства, необходимые вашему представлению
  • Привязать к этим свойствам в Xaml

Например:

 public class EmployeeListViewModel
{
  public ObservableCollection<Employee> AllEmployees {get;private set;}
  public string FirstName {get;set;}
  public string LastName {get;set;}
  public int? Age {get;set;}  
  public ICommand NewEmployeeCommand {get;set;}

  //You need to connect to this method by using a Delegate/RelayCommand see link below
  public void AddNewEmployee()
  {
    //Add your real code here to actually insert into the db
    var result = InsertEmployeeIntoDatabase(FirstName,LastName,Age);
    //You probably want to add this new employee to the list now ;)
    AllEmployees.Add(result);
    //Now you probably want to reset your fields
    FirstName = null;
    LastName = null;
    Age = null;
  }
}
  

Нажмите здесь для реализации команды делегирования

А затем просто отредактируйте свой xaml следующим образом:

 <ItemsControl ItemsSource="{Binding AllEmployees}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBox Width="100" Text="{Binding FirstName}" Margin="4"/>
                        <TextBox Width="100" Text="{Binding LastName}" Margin="4"/>
                        <TextBox Width="100" Text="{Binding Age}" Margin="4"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
</ItemsControl>
<!-- For new Employee Details -->
<StackPanel>
        <TextBox Text={Binding FirstName}"/>
        <TextBox Text={Binding LastName}"/>
        <TextBox Text={Binding Age}"/>
        <Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
  

Ответ №2:

Вы могли бы передавать ссылки в параметре command:

 <StackPanel>
    <TextBox x:Name="FirstName"/>
    <TextBox x:Name="LastName"/>
    <Button Content="New" Command="{Binding NewEmployeeCommand}">
        <Button.CommandParameter>
            <x:Array Type="{x:Type TextBox}">
                <x:Reference Name="FirstName"/>
                <x:Reference Name="LastName"/>
            </x:Array>
        </Button.CommandParameter>
    </Button>
</StackPanel>
  

В зависимости от того, какое событие вы используете, вы вводите параметр в регистр и получаете значения:

 TextBox[] textBoxes = e.Parameter as TextBox[]; //RoutedEvent
TextBox[] textBoxes = parameter as TextBox[]; //If the executed handler provides the parameter

string firstName = textBoxes[0].Text;
string lastName = textBoxes[1].Text;
//create entry; store in DB
  

Через привязку:

 <Button.CommandParameter>
    <local:MyEntry FirstName="{Binding ElementName=FirstName, Path=Text}"
                   LastName="{Binding ElementName=LastName, Path=Text}"/>
</Button.CommandParameter>
  
 MyEntry entry = parameter as MyEntry;
//store in DB
  

Комментарии:

1. Спасибо за ваш ответ. Но будет ли это шаблоном MVVM?

2. Я не знаю, извините, я только недавно начал изучать MVVM. Вы могли бы создать объект в CommandParameter и связать его значения, я думаю, это было бы чище.

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

Ответ №3:

вы не читаете значения текстового поля. вам нужен NewEmployeeViewModel и привязать текстовые поля к свойствам.

Редактировать:

просто создайте класс с INotifyPropertyChanged и нужными вам свойствами.

 public class NewEmployee : INotifyPropertyChanged 
{
   public string FirstName
   {
     get{return this._firstname;}
     set{this._firstname = value;
         OnPropertyChanged("FirstName");}
   }
   //... other properties
 }
  

xaml

 <StackPanel DataContext={Binding MyNewEmployeeProperty}>
    <TextBox x:Name="FirstName" Text={Binding FirstName}/>
    <TextBox x:Name="LastName" Text={Binding LastName}/>
    <TextBox x:Name="Age" Text={Binding Age}/>
    <Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
  

Комментарии:

1. @Blindmeis: не могли бы вы дать мне какой-нибудь код, как это сделать? Спасибо

2. @Blindmeis: Спасибо, чувак. Но как я мог бы сопоставить эти текстовые поля с моей базой данных сотрудников.

3. я не знаю ваш DAL, но если у вас есть способ вставить новую строку. просто выполните условия. вы не сопоставляете текстовые поля со своей базой данных. текстовые поля привязаны к вашей виртуальной машине, и у вашей виртуальной машины есть все необходимые данные. используете ли вы NHibernate или другой ORM?

4. небольшая задержка.. я использую Linq-to-SQL

5. я не знаю Linq-to-Sql, но я думаю, что там тоже есть объекты? итак, возможно, у вас есть объект с именем EmployeeEntity. если это так, просто сопоставьте данные вашего свойства с вашим объектом и вызовите объект. Сохраните () в вашей новой команде. если объект Linq-to-Sql реализует INotifyProepertyChanged, вы можете привязать объект непосредственно к вашему представлению. Кстати, Хосе опубликовал полный пример

Ответ №4:

Я получил правильный ответ.

Моя новая форма ввода в xmal должна быть

 <StackPanel>
        <TextBox Text={Binding Employee.FirstName}"/>
        <TextBox Text={Binding Employee.LastName}"/>
        <TextBox Text={Binding Employee.Age}"/>
        <Button Content="New" Command="{Binding NewEmployeeCommand}"/>
</StackPanel>
  

Мой файл cs

 public class EmployeeListViewModel : INotifyPropertyChanged 
{
  Employee _employee;
  RelayCommand _addNewEmployee;
  EmployeeRepository _employeeRepository;

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

  }    

  public void NewEmployeeCommand()
  {
    if(_addNewEmployee == null)
    {
       _addNewEmployee = new RelayCommand( param => NewEmployeeCommandExecute(), 
                                           param => NewEmployeeCommandCanExecute
                                          );
    }
  }

  void NewEmployeeCommandExecute()
  {
         _employeeRepository.Add(Employee); 
         _employeeRepository.Save();
   }

   bool NewEmployeeCommandCanExecute
   {
         get
         {
            return true;
         }
   }
}