私はWPFが比較的新しく、MVVMで作業しているアプリケーションを構築するために、MVVMパターンとObservableCollectionでのデータバインディングのしくみを理解しようとしています。メインウィンドウを持つアプリケーションのサンプルを作成しました。ここでは、ユーザーがどのボタンを押すかに応じて、異なるビュー(UserControl)が表示されます。一般的な考え方は、ユーザがデータベースからいくつかの要素のデータにアクセスし(例:顧客、製品など)、既存の要素を新規に追加したり編集したり削除したりできるようになるというものです。
So, there is a CustomerView, with its CustomerViewModel, and a ProductView, with its ProductViewModel respectively. Also, there are two classes (Customer.cs & Product.cs) that represent the Models. The structure of the project is displayed here.
MainWindow.xamlは次のとおりです。
そして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は次のとおりです。
そしてCustomerViewModel.cs:
public class CustomerViewModel : ObservableCollection
{
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);
}
}
Please note that the ProductView.xaml & ProductViewModel.cs are similar. Currently, when the user presses the "Customers" or the "Products" button of the MainWindow, then the respective View is displayed and the collections are loaded according to the LoadCustomers (or LoadProducts) method, which is called by the ViewModel's constructor. Also, when the user selects a different object from the ComboBox, then its properties are displayed correctly (i.e. Id, Name, etc.). The problem is when the user adds a new (or deletes an existing) element.
Question 1: Which is the correct and best way to update a changed Observable Collection of an element and reflect its changes in the UI (Combobox, properties, etc.)?
Question 2: During testing this project I noticed that the constructor of the ViewModels (consequently the LoadCustomers & LoadProducts method) are called twice. However, it is only called when the user presses the Customers or the Products button respectively. Is it also called via the XAML data binding? Is this the optimum implementation?
あなたの最初の質問は基本的にはUXの質問です、正しいまたは "最良の"方法はありません。あなたは間違いなくある種の ItemsControl
を使うことになるでしょう、しかしそれはあなたがあなたのユーザーがそれとどのようにやり取りしたいかに大きく依存します。
2番目の質問に、あなたはあなたのコードにいくつかの間違いがあります:
Instantiates a new view model, apart from the one that the main application created
Grid DataContext="{StaticResource ResourceKey=customerVM}"
Then uses this "local" view model, ignoring the inherited one from the main application
そのため、コンストラクタが2回起動し、2つのインスタンスを構築しているのがわかります。ローカルVMを排除し、グリッドにDCを割り当てないでください。その他の問題
The DataContext assignment is total unnecessary, by virtue of being in the data template it's data context is already set up
Yuck, you should have a "MainViewModel" with a property that this uses. Don't make it be the whole data context
Lack of commands for your button clicks (related to the bullet above)
あなたの最初の質問は基本的にはUXの質問です、正しいまたは "最良の"方法はありません。あなたは間違いなくある種の ItemsControl
を使うことになるでしょう、しかしそれはあなたがあなたのユーザーがそれとどのようにやり取りしたいかに大きく依存します。
2番目の質問に、あなたはあなたのコードにいくつかの間違いがあります:
Instantiates a new view model, apart from the one that the main application created
Grid DataContext="{StaticResource ResourceKey=customerVM}"
Then uses this "local" view model, ignoring the inherited one from the main application
そのため、コンストラクタが2回起動し、2つのインスタンスを構築しているのがわかります。ローカルVMを排除し、グリッドにDCを割り当てないでください。その他の問題
The DataContext assignment is total unnecessary, by virtue of being in the data template it's data context is already set up
Yuck, you should have a "MainViewModel" with a property that this uses. Don't make it be the whole data context
Lack of commands for your button clicks (related to the bullet above)
MVVMのリストで必要な変更通知は3種類あります。
高度なオプションとして、生のCollectionではなくCollectionViewを公開することを検討してください。 WPFのGUI要素は生のコレクションにはバインドされず、CollectionViewのみにバインドされます。しかし、あなたが彼らに手渡さなければ、彼らは彼ら自身を創造するでしょう。
MVVMのリストで必要な変更通知は3種類あります。
高度なオプションとして、生のCollectionではなくCollectionViewを公開することを検討してください。 WPFのGUI要素は生のコレクションにはバインドされず、CollectionViewのみにバインドされます。しかし、あなたが彼らに手渡さなければ、彼らは彼ら自身を創造するでしょう。