Я относительно новичок в WPF и пытаюсь понять шаблон MVVM и то, как привязка данных работает с ObservableCollection, чтобы создать приложение, над которым я работаю с MVVM.Я создал образец моего приложения с MainWindow, в котором, в зависимости от того, какую кнопку нажимает пользователь, отображается другое представление (UserControl).Общая идея заключается в том, что пользователь будет иметь доступ к данным некоторых элементов из базы данных (например, клиенты, продукты и т. Д.) И сможет добавлять новые, редактировать или удалять существующие.
Итак, есть CustomerView с его CustomerViewModel и ProductView с его ProductViewModel соответственно.Кроме того, есть два класса (Customer.cs & Product.cs), которые представляют Модели.Структура проекта отображается здесь .
MainWindow.xaml выглядит следующим образом:
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:CustomerViewModel}">
<views:CustomerView DataContext="{Binding}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ProductViewModel}">
<views:ProductView DataContext="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="80*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="btnCustomers" Click="btnCustomers_Click" Content="Customers" Width="80" Height="50" Margin="10"/>
<Button x:Name="btnProducts" Click="btnProducts_Click" Content="Products" Width="80" Height="50" Margin="10"/>
</StackPanel>
<Grid Grid.Column="1">
<ContentControl Grid.Column="0" Content="{Binding}"/>
</Grid>
</Grid>
и код MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public CustomerViewModel customerVM;
public ProductViewModel productVM;
public MainWindow()
{
InitializeComponent();
}
private void btnCustomers_Click(object sender, RoutedEventArgs e)
{
if (customerVM == null)
{
customerVM = new CustomerViewModel();
}
this.DataContext = customerVM;
}
private void btnProducts_Click(object sender, RoutedEventArgs e)
{
if (productVM == null)
{
productVM = new ProductViewModel();
}
this.DataContext = productVM;
}
}
Наконец, CustomerView.xaml выглядит следующим образом:
<UserControl.Resources>
<viewModel:CustomerViewModel x:Key="customerVM"/>
<!-- Styling code here...-->
</UserControl.Resources>
<Grid DataContext="{StaticResource ResourceKey=customerVM}">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="7*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Text="Customers" FontSize="18"/>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<ComboBox x:Name="cmbCustomers" Grid.Column="0" VerticalAlignment="Top"
IsEditable="True"
Text="Select customer"
ItemsSource="{Binding}"
DisplayMemberPath="FullName" IsSynchronizedWithCurrentItem="True">
</ComboBox>
<StackPanel Grid.Column="1" Margin="5">
<StackPanel Orientation="Horizontal">
<TextBlock Grid.Column="0" Text="Id:" />
<TextBlock Grid.Column="1" x:Name="txtId" Text="{Binding Path=Id}" FontSize="16"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Grid.Column="0" Text="Name:" />
<TextBlock Grid.Column="1" x:Name="txtFirstName" Text="{Binding Path=FirstName}" FontSize="16"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Grid.Column="0" Text="Surname:" />
<TextBlock Grid.Column="1" x:Name="txtLastName" Text="{Binding Path=LastName}" FontSize="16"/>
</StackPanel>
</StackPanel>
</Grid>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="btnAddNew" Content="Add New" Click="btnAddNew_Click"/>
<Button x:Name="btnDelete" Content="Delete Customer" Click="btnDelete_Click"/>
</StackPanel>
</Grid>
и CustomerViewModel.cs:
public class CustomerViewModel : ObservableCollection<Customer>
{
public CustomerViewModel()
{
LoadCustomers();
}
private void LoadCustomers()
{
for (int i = 1; i <= 5; i++)
{
var customer = new Customer()
{
Id = i,
FirstName = "Customer_" + i.ToString(),
LastName = "Surname_" + i.ToString()
};
this.Add(customer);
}
}
public void AddNewCustomer(int id)
{
var customer = new Customer()
{
Id = id,
FirstName = "Customer_" + id.ToString(),
LastName = "Surname_" + id.ToString()
};
Add(customer);
}
}
Обратите внимание, что ProductView.xaml & ProductViewModel.cs похожи.В настоящее время, когда пользователь нажимает кнопку «Клиенты» или «Продукты» в MainWindow, отображается соответствующее представление, и коллекции загружаются в соответствии с методом LoadCustomers (или LoadProducts), который вызывается конструктором ViewModel.Кроме того, когда пользователь выбирает другой объект из ComboBox, тогда его свойства отображаются правильно (т. Е. Идентификатор, имя и т. Д.).Проблема заключается в том, что пользователь добавляет новый (или удаляет существующий) элемент.
Вопрос 1 : Какой правильный и лучший способ обновить измененную Наблюдаемую коллекциюэлемент и отражать его изменения в пользовательском интерфейсе (Combobox, свойства и т. д.)?
Вопрос 2 : во время тестирования этого проекта я заметил, что конструктор ViewModels (следовательно, LoadCustomers & LoadProductsметод) вызываются дважды.Однако он вызывается только тогда, когда пользователь нажимает кнопку «Клиенты» или «Продукты» соответственно.Это также вызывается через привязку данных XAML?Это оптимальная реализация?