鉴于下面的类,我正在寻找使ExecuteQuery
类的Parameters与Query
类的Parameters保持同步的最佳方法。
我正在WPF项目中使用两个视图和视图模型,一个视图是定义模型Query
,将DataGrid绑定到Parameters
。另一个视图是定义模型ExecuteQuery
,该模型具有ComboBox以选择目标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());
});
我可以尽力而为,但是在这里问这个问题,以了解一种专家解决方案,以最少的代码更改来解决此类重复出现的问题,并确定大多数人使用的任何模式。
感谢Holger的评论。最后,这就是我通过这么多事件接线实现的方式,这些事件接线似乎有点脏。不知道是否有更好更好的方法。
我发布此问题的初衷是寻求从我的领域对象中抽象出这种逻辑的任何熟练方法。
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;
}
}
}