#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;
}
}
}