複雑なモデルのコレクションがあり、それぞれに他の複雑なモデルへのインターフェイスインスタンスのコレクションが含まれています。これらの親と子の複雑なモデルを表示して、親と子の複雑なモデルのすべてのプロパティを編集できるようにする必要があります。
このデータを最適に表示し、親オブジェクトと子オブジェクトのプロパティを個別に編集したり、複数のセルを選択してコンテキストメニューをクリックしたりする(つまり、複数の親間で子モデルの同じプロパティ値を変更する)ことができるようにするにはどうすればよいですか? ?また、編集メカニズム(現在はDataGridセル)内から検索を介して、モデルプロパティ値を他の複雑なモデルインスタンスに設定するなどのアクションを実行できる必要がありますか?
以下は、私がアプリケーションで使用しているものに近いクラスの一般的な例です。
enum ChildType
{
One,
Two,
Three
}
class ComplexType
{
public long ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
class IChildModel
{
ChildType Type { get; set; }
string Name { get; set; }
}
class ChildModel1 : IChildModel
{
public ChildType Type { get; set; }
public string Name { get; set; }
public string Property1 { get; set; }
public decimal Property2 { get; set; }
public ComplexType Property3 { get; set; }
}
class ChildModel2 : IChildModel
{
public ChildType Type { get; set; }
public long Property1 { get; set; }
public string Property2 { get; set; }
}
class Parent
{
public long ID { get; set; }
public string Name { get; set; }
public CustomObservableCollection<IChildModel> Children { get; set; }
}
class ViewModel
{
public CustomObservableCollection<Parent> Parents { get; set; }
}
これまで、DataGridを使用してアプリケーションを実装し、リフレクションを使用してビューコードビハインドの列を動的に生成しました。子複合オブジェクトインスタンスの列のバインドでは、CustomObservableCollection <>(この場合はジェネリック値[enum ChildType]によるインデックス付けを可能にするカスタムコレクション)の添え字を使用します。特にバインディングにより、複数の親の子インスタンス間で同じプロパティに値を適切に設定することが困難になりました(列の複数選択とコンテキストメニューのクリックによる値の設定)。繰り返しになりますが、私はビューのコードビハインドでこの種の大量の変更を処理しており、バインディングパスの解析を使用してプロパティ値を設定しています(間違っていると感じます。そのようにするのは嫌です)。選択した子をViewModelに設定し、プロパティ名とプロパティの新しい値をViewModelのコマンドに渡して変更を加えられるようにしたいと思います。コマンドに子の型、プロパティ、新しい値を渡すことができたとしても、それは素晴らしいことだと思います(私は思います)。
Google、stackoverflow、Code Projectなどを通じた調査で、現在の解決策が示されましたが、問題について間違って考えていると感じており、これにはより良いMVVMアプローチが必要です。
編集
このアプリケーションの主な焦点は、ユーザーが複数のインスタンスの値を比較できるビューで複数の親と子のモデルインスタンスを編集できるようにし、同じタイプの複数のオブジェクトに親または子のプロパティの値を設定できるようにすることです。同じ値に設定します(つまり、Parent1とParent2の両方にChildModel1があり、ユーザーは両方の親オブジェクトのChildModel1のProperty3の名前を「X」に設定したい)。ただし、アプリケーションは親オブジェクトと子オブジェクトのプロパティを個別に編集できるようにする必要があります(DataGridは要件を適切に満たしているようです)。これらの要件を満たすために、ビューに動的な列の作成を実装しました。以下は、このロジックがどのように見えるかの一般的な例です。
private void DataGrid_TargetUpdated(object sender, DataTransferEventArgs e)
{
var vm = DataContext as ViewModel;
if (vm != null && vm.Parents != null) {
List<ChildType> processedChildTypes = new List<ChildType>();
foreach (var parent in vm.Parents) {
for (int childIndex = 0; childIndex < parent.Children.Count; ++childIndex) {
var child = vm.Children[childIndex];
if (!processedChildTypes.Contains(child.Type)) { // Ensure each child type is only processed once
processedChildTypes.Add(child.Type);
CreateChildPropertyColumns(processedChildTypes, child);
}
}
}
}
private void CreateChildPropertyColumns(List<ChildType> processedChildTypes, IChildModel child)
{
PropertyInfo[] childProperties = child.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); // Only use properties declared on the child type
Type childInterfaceType = typeof(IChildModel);
foreach (PropertyInfo childProperty in childProperties) {
// Only create a column if the property is editable
if (childProperty.CanWrite) {
if (childInterfaceType.IsAssignableFrom(childProperty.PropertyType)) {
var subChild = childProperty.GetValue(child, null) as IChildModel;
if (subChild != null && !processedChildTypes.Contains(subChild.Type)) {
processedChildTypes.Add(subChild.Type);
CreateChildPropertyColumns(processedChildTypes, subChild);
}
}
else
dataGrid.Columns.Add(CreateChildPropertyColumn(child.Type, childProperty));
}
}
}
private DataGridColumn CreateChildPropertyColumn(ChildType childType, PropertyInfo propertyInfo)
{
DataGridColumn column = null;
var binding = new Binding(string.Format("Children[{0}].{1}", childType, propertyInfo.Name));
/* Create column based on PropertyInfo here */
/* Default case is a text column */
column = new DataGridTextColumn() { Binding = binding };
column.Header = propertyInfo.Name;
return column;
}