В рамках MVVM разрабатываю приложение для базы данных SQlite. База состоит из таблиц: Orders(Id(Первичный ключ), Number, NameOfItem, Employee(ссылка на сотрудника из таблицы Staff)) Staff(Id(Первичный ключ), LastName, Name, MiddleName, DateofBirth, Gender, Unit)
На форме для добавления заказа(OrderWindow) необходимо сделать Combobox "Сотрудник" и вывести в него данные из таблицы Staff(для примера что угодно, хоть Id, хоть Name), чтобы выбранный элемент, в последствии, записывался в таблицу Order. Гуглил этот вопрос, но варианты решений рушат MVVM...
На данный момент есть один вариант, как вывести данные(фамилию) из таблицы Staff в comboBox: DataContext = new ViewModel(); и <ComboBox ItemsSource="{Binding Staffs}" DisplayMemberPath="LastName"/> для View OrderWindow, но тогда не выводятся значения выбранного элемента таблицы Order, а если же убрать DataContext = new ViewModel(); и оставить
`
public Order Order { get; private set; }
public OrderWindow(Order p)
{
InitializeComponent();
Order = p;
DataContext = Order;
//DataContext = new ViewModel();
}`
то данные из таблицы Order выводятся, но comboBox не заполняется элементами из Staff.
Может знает кто вариант решения проблемы? Так как основной код строился на основе статьи из Метанита (https://metanit.com/sharp/wpf/22.1.php)
ViewModel
{ public class ViewModel : INotifyPropertyChanged { ApplicationContext db; RelayCommand addCommand; RelayCommand editCommand; IEnumerable orders; RelayCommand addCommandStaff; RelayCommand editCommandStaff; IEnumerable staffs;
public IEnumerable<Order> Orders
{
get { return orders; }
set
{
orders = value;
OnPropertyChanged("Orders");
}
}
public IEnumerable<Staff> Staffs
{
get { return staffs; }
set
{
staffs = value;
OnPropertyChanged("Staffs");
}
}
public ViewModel()
{
db = new ApplicationContext();
db.Orders.Load();
Orders = db.Orders.Local.ToBindingList();
db.Staffs.Load();
Staffs = db.Staffs.Local.ToBindingList();
}
public RelayCommand AddCommand
{
get
{
return addCommand ??
(addCommand = new RelayCommand((o) =>
{
OrderWindow orderWindow = new OrderWindow(new Order());
if (orderWindow.ShowDialog() == true)
{
Order order = orderWindow.Order;
db.Orders.Add(order);
db.SaveChanges();
}
}));
}
}
public RelayCommand EditCommand
{
get
{
return editCommand ??
(editCommand = new RelayCommand((selectedItem) =>
{
if (selectedItem == null) return;
Order order = selectedItem as Order;
Order vm = new Order()
{
Id = order.Id,
Number = order.Number,
NameOfItem = order.NameOfItem,
Employee = order.Employee
};
OrderWindow orderWindow = new OrderWindow(vm);
if (orderWindow.ShowDialog() == true)
{
order = db.Orders.Find(orderWindow.Order.Id);
if (order != null)
{
order.Number = orderWindow.Order.Number;
order.NameOfItem = orderWindow.Order.NameOfItem;
order.Employee = orderWindow.Order.Employee;
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
}
}
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
OrderWindow.cs
public partial class OrderWindow : Window
{
public Order Order { get; private set; }
public Staff Staff1 { get; private set; }
public OrderWindow(Order p)
{
InitializeComponent();
Order = p;
DataContext = Order;
//DataContext = new ViewModel();
}
}
Класс Order
public class Order : INotifyPropertyChanged
{
private int number;
private string nameofitem;
private string employee;
public int Id { get; set; }
public int Number
{
get { return number; }
set
{
number = value;
OnPropertyChanged("Number");
}
}
public string NameOfItem
{
get { return nameofitem; }
set
{
nameofitem = value;
OnPropertyChanged("NameOfItem");
}
}
public string Employee
{
get { return employee; }
set
{
employee = value;
OnPropertyChanged("Employee");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Класс Staff
public class Staff : INotifyPropertyChanged
{
private string lastname;
private string name;
private string middlename;
private DateTime dateofbirth;
public enum gender
{
male = 1,
female = 2,
};
private string unit;
public int Id { get; set; }
public string LastName
{
get { return lastname; }
set
{
lastname = value;
OnPropertyChanged("LastName");
}
}
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
public string MiddleName
{
get { return middlename; }
set
{
middlename = value;
OnPropertyChanged("MiddleName");
}
}
public DateTime DateOfBirth
{
get { return dateofbirth; }
set
{
dateofbirth = value;
OnPropertyChanged("DateOfBirth");
}
}
private gender _gender;
public gender Gender
{
get { return _gender; }
set
{
_gender = value;
OnPropertyChanged("Gender");
}
}
public string Unit
{
get { return unit; }
set
{
unit = value;
OnPropertyChanged("Unit");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
OrderWindow.XAML
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="Номер" />
<TextBlock Text="Название товара" Grid.Row="1" />
<TextBlock Text="Сотрудник" Grid.Row="2" />
<TextBlock Text="Тест" Grid.Row="3" />
<TextBox Text="{Binding Number}" Grid.Column="1" />
<TextBox Text="{Binding NameOfItem}" Grid.Column="1" Grid.Row="1" />
<TextBox Text="{Binding Employee}" Grid.Column="1" Grid.Row="2" />
<ComboBox ItemsSource="{Binding Staffs}" DisplayMemberPath="LastName" Grid.Column="1" Grid.Row="3" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Grid.Row="4" Grid.Column="1">
<Button IsDefault="True" Click="Accept_Click" MinWidth="60" Margin="5">OK</Button>
<Button IsCancel="True" MinWidth="60" Margin="5">Отмена</Button>
</StackPanel>
</Grid>
</Window>
но тогда не выводятся значения выбранного элемента таблицы Order- ну, наверно потому, что источник данных, который вы задаете какDataContext(ViewModel), не содержит в себеOrder(и его данные). Посмотрите еще раз, что вы делаете и как, не знаю, нарисуйте себе на листочке связи, что и где находится. Сейчас я думаю, что вы просто запутались. – EvgeniyZ Oct 16 '20 at 17:33Binding Staffs- где свойствоStaffsвOrder? Почему оно должно отобразить то, чего нет? Ну и обратное, допустимBinding Employee, где свойствоEmployeeвViewModel? Вы уж определитесь, какие данные и как хотите отобразить. Также я заметилClick="Accept_Click"- по правилам MVVM это плохо, используйте команды. – EvgeniyZ Oct 16 '20 at 19:11Staffs в Order- а какая у них связь? Вот допустим, есть "сотрудники", а также есть один заказ. Вы сейчас хотите в один заказ запихнуть список сотрудников, вопрос - зачем? Почему заказ знает про сотрудников?во вью модели тоже есть обработка этого- где вViewModel(классе), эти свойства? Я вижу, напримерIEnumerable<Order> Orders- это как я понял список заказов, выводите его, далее берите то, что выбрано в отдельное свойство (или используйте IsSynchronizedWithCurrentItem), а от него уже привязывайтесь (прим:{Binding Prop.Number}) – EvgeniyZ Oct 16 '20 at 19:33Запихнуть одно в другое для окна добавления или редактирования заказа- но тем самым вы нарушаете кучу других правил программирования, например S из SOLID, которое говорит о единой ответственности ваших сущностей. Ваш класс заказа должен содержать лишь ссылку на сотрудника (Staff), не сам список всех сотрудников. А вот окно редактирования, должно уже эти данные подгружать из разных мест и выводить пользователю для выбора. Как я уже говорил выше, просто сделайте классы, которые будут отвечать за что-то одно и дальше хоть на листочке их свяжите друг с другом, посмотрите как лучше делать. – EvgeniyZ Oct 16 '20 at 19:50