【问题标题】:How to keep Properties in sync如何保持属性同步
【发布时间】:2020-01-06 19:12:13
【问题描述】:

鉴于以下类,我正在寻找使ExecuteQuery 类的ParametersQuery 类的Parameters 保持同步的最佳方法。 p>

我正在使用两个视图和视图模型在 WPF 项目中工作,一个视图是定义模型 Query,有一个 DataGrid 绑定到 Parameters。另一个视图是定义模型ExecuteQuery,它有ComboBox来选择目标Query对象。一旦选择它,我想将参数从 Query 复制到 ExecuteQuery 以便同步,并且可以跟踪任何集合和属性更改并相应地反映在 ExecuteQuery 中。

public class NameParameter : Entity
{
    private string _name;
    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }
}

public class KeyValueParameter : ClientEntity
{
    private string _name;
    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }

    private string _value;
    public string Value
    {
        get => _value;
        set => SetProperty(ref _value, value);
    }
}

public class Query
{
    private ObservableCollection<NameParameter> _parameters = new ObservableCollection<NameParameter>();
    public IEnumerable<NameParameter> Parameters => _parameters.AsEnumerable();

    public void AddParameter()
    {
        _parameters.Add(new NameParameter());
    }
}

public class ExecuteQuery
{
    private Query _query;
    public Query Query
    {
        get => _query;
        set => SetProperty(ref _query, value);
    }

    private ObservableCollection<KeyValueParameter> _parameters = new ObservableCollection<KeyValueParameter>();
    public IEnumerable<KeyValueParameter> Parameters => _parameters.AsEnumerable();
}

到目前为止,我已经使用 Automapper 通过以下配置映射不同的类型,但我仍然不确定这是否是解决此问题的正确方法。

var configuration = new MapperConfiguration(cfg => {
    cfg.AllowNullCollections = true;
    cfg.CreateMap<NameParameter, KeyValueParameter>()
        .ForMember(d => d.Value, o => o.Ignore());
});

我可以通过一些努力来实现它,但是在这里问这个问题是为了知道一个专家解决方案,以最少的代码更改来解决这种重复的问题,并确定大多数人使用的任何模式。

【问题讨论】:

  • 有什么原因,你存储了两次数据?为什么 ExecuteQuery.Parameters 不能只返回一个变形的 _query.Paramters ?
  • Query 列出了多个 ExecuteQuery 可以使用的命名参数,它应该具有相同的参数,以 KeyValueParameter 的形式存储附加值。
  • 可以转换这个,然后访问ExcuteQuery.Parameters。我认为没有理由存储它。 ExecuteQuery 没有修改它的副本,或者是吗?
  • 我将限制对来自查询的名称的修改,但最终它应该单独维护这些数据以保存每个参数的值。目前,我在 ExecuteQuery 中有一个 DataGrid,显示只读名称列和可编辑值列。
  • 不,CollectionChanged 涵盖了所有内容。添加/删除/编辑项目。处理程序看起来像_parameters = _query.Parameters.Select(x =&gt; new KeyValueParameter( x.whatever..)) 这一个班轮不够优雅?

标签: c# wpf automapper prism


【解决方案1】:

感谢 Holger 的 cmets。最后,这就是我通过这么多看起来有点脏的事件接线来实现它的方式。不确定是否有更好更干净的方法。

我发布这个问题的初衷是寻求任何熟练的方法来从我的域对象中抽象出这个逻辑。

public class Query
{
    private ObservableCollection<NameParameter> _parameters = new ObservableCollection<NameParameter>();
    public IEnumerable<NameParameter> Parameters => _parameters.AsEnumerable();

    public void AddParameter()
    {
        _parameters.Add(new NameParameter());
    }

    public void SubscribeParametersCollectionChanges(NotifyCollectionChangedEventHandler handler)
    {
        _parameters.CollectionChanged += handler;
    }
}

public class ExecuteQuery
{
    public ExecuteQuery()
    {
        PropertyChanged += ExecuteQuery_PropertyChanged;
    }

    private void ExecuteQuery_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Query))
            OnQuerySelection();
    }

    private Query _query;
    public Query Query
    {
        get => _query;
        set => SetProperty(ref _query, value);
    }

    private ObservableCollection<KeyValueParameter> _parameters = new ObservableCollection<KeyValueParameter>();
    public IEnumerable<KeyValueParameter> Parameters => _parameters.AsEnumerable();

    private void OnQuerySelection()
    {
        // subscribe to NamedParameters collection changed events
        DataElement?.SubscribeParametersCollectionChanges(Parameters_CollectionChanged);
        // calling this method explicitly so that if there are already Parameters in Source, bring them right away
        Parameters_CollectionChanged(this, null);
    }

    private void Parameters_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // subscribe to each object property changed events in NamedParameters 
        foreach (var namedParameter in Query.Parameters)
            if (namedParameter is INotifyPropertyChanged npc)
                npc.PropertyChanged += Parameters_PropertyChanged;
        // copying parameters from source to target
        _parameters = new ObservableCollection<KeyValueParameter>(
            Query.Parameters.Select(x => new KeyValueParameter(x.Name)));
        // raising event to notify UI for this change
        RaisePropertyChanged(nameof(Parameters));
    }

    private void Parameters_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Name))
        {
            var namedParameter = Query.Parameters.ToList();
            for (var i = 0; i < namedParameter.Count; i++)
                _parameters[i].Name = namedParameter[i].Name;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多