关于将嵌套hierarchical对象的字段映射到平面列表的意见?

问题描述 投票:0回答:2

我正在写一个工具,它可以访问一个word文档,并在文档中预填数据。该文档有一个子集 自定义文档属性,每个属性都有一个名称,其值用于更新文档中的字段。

我的ViewModel应该既能从这些文档属性的数据中发起更新它的实例,又能把它的值写回来并更新文档的字段。

就像这样。

class PersonVM : INotifyPropertyChanged 
{
  // properties
  string Name { get; set; }
  string PhoneNumber { get; set; }

  // methods to get data or save data of this properties to or from the word document
  void saveMyPropertyValuesToWord()
  {
    // …
  } 

  void updateMyPropertiesFromWord()
  {
     // …
  }
}

class ProjectVM : INotifyPropertyChanged
{
  int ProjectNumber { get; set; }
  PersonVM Manager { get; set; }
  PersonVM Mechanic1 { get; set; }
  PersonVM Mechanic2 { get; set; }

  void saveMyPropertyValuesToWord()
  {
     Manager.saveMyPropertyValuesToWord();
     Mechanic1.saveMyPropertyValuesToWord();
     Mechanic2.saveMyPropertyValuesToWord();

     // handle ProjectNumber  etc.
  } 

  void updateMyPropertiesFromWord()
  {
     Manager.updateMyPropertiesFromWord();
     Mechanic1.updateMyPropertiesFromWord();
     Mechanic2.updateMyPropertiesFromWord();

     // handle ProjectNumber  etc.
  }

  class CompanyVM : INotifyPropertyChanged
  {
    string Name { get; set; }
    PersonVM Owner { get; set; } 
    ProjectVM Project1 { get; set; }
    ProjectVM Project2 { get; set; }

    // …
  }

  // …
}

现在我有一个具有静态字符串属性的类 为word文档中可能存在的每一个文档属性提供静态字符串属性 我想从这些属性中加载相应的数据。

class WordUtils 
{
  // Company
  static string CompanyName = "dp_CompanyName";
  // Company.Owner
  static string CompanyOwnerName = "dp_CompanyOwnerName";
  static string CompanyOwnerPhone = "dp_CompanyOwnerPhone";
  // Company.Project1
  static string CompanyProject1Number = "dp_CompanyProject1Number";
  // Company.Project1.Manager
  static string CompanyProject1ManagerName = "dp_CompanyProject1ManagerName";
  static string CompanyProject1ManagerPhone = "dp_CompanyProject1ManagerPhone";
  // Company.Project1.Mechanic1

  // … etc
}

现在回到实现这些属性的问题上 PersonVM.saveMyPropertyValuesToWord() - 我想到了这样的东西。

void saveMyPropertyValuesToWord()
{
   Name = MyApp.MyWordDocument.GetCustomProperty(WordUtils.OwnerName);
}

但在这里,我需要知道在类的层面上,这个东西到底是从哪个实例中调用的(例如,我是哪个PersonVM的。公司.业主项目1.经理 或?),以便决定我需要提供哪个WordUtils.Name。

我不知道应该怎么做,也许把PersonVM做成抽象的,然后为每个角色做一个新的类(这又只能有一个自己的实例,在我看来不是很美观)? 我也简单地看了一下Attributes,期望这些在这种情况下可能会有帮助。也许我漏掉了一些明显的东西,但是广泛的搜索解决这个问题的方法到目前为止没有结果。

c# wpf mvvm office-interop
2个回答
1
投票

不如这样吧。

class Property
{
    public string Key { get; }
    public string Value { get; set; }
    public Property(string key) => Key = key;
}

interface IPropertyTree
{
    IEnumerable<IPropertyTree> ChildNodes { get; }
    IEnumerable<Property> Properties { get; }
}
class PersonVM : IPropertyTree
{
    private readonly string prefix;

    public PersonVM(string prefix)
    {
        Name = new Property(prefix + "Name" );
        PhoneNumber = new Property(prefix + "PhoneNumber");
    }

    public Property Name { get;  }
    public Property PhoneNumber { get;  }
    public IEnumerable<IPropertyTree> ChildNodes => Enumerable.Empty<IPropertyTree>();
    public IEnumerable<Property> Properties => new[] {Name, PhoneNumber};
}
static class PropertyTreeExtensions
{
    public static void Update(this IPropertyTree self)
    {
        foreach (var property in self.Flatten().SelectMany(tree => tree.Properties))
        {
            property.Value = MyApp.MyWordDocument.GetCustomProperty(property.Key);
        }
    }

    public static IEnumerable<IPropertyTree> Flatten(this IPropertyTree self)
    {
        var stack = new Stack<IPropertyTree>();
        stack.Push(self);
        while (stack.Count > 0)
        {
            var current = stack.Pop();
            yield return current;
            foreach (var child in current.ChildNodes)
            {
                stack.Push(child);
            }
        }
    }
}

这应该允许每个属性都有一个唯一的键 并保持键和属性值的紧密耦合。它还应该允许你把保存更新逻辑移到一个集中的地方。


1
投票

当然,你可以实现一个具体的类 IPerson 并对每个类型的实现进行硬编码。

因为你在创建一个实例的时候就知道了人的类型。PersonVMM你可以添加一个属性 PersonTypeId 并从构造函数中设置。

void SomeMethod()
{
  var personVm = new PersonVM(WordUtils.OwnerName);
}

class PersonVM : INotifyPropertyChanged 
{
  // properties
  string PersonTypeId { get; set; }
  string Name { get; set; }
  string PhoneNumber { get; set; }

  public PersonVM() 
  {}

  public PersonVM(string personTypeId) 
  {
    PersonTypeId = personTypeId;
  }

  // methods to get data or save data of this properties to or from the word document
  void saveMyPropertyValuesToWord()
  {
    Name = MyApp.MyWordDocument.GetCustomProperty(PersonTypeId);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.