C# 从两个不同的源设置依赖项属性:需要不同的后处理吗
我有以下WPF代码。您可以在那里的评论中看到,我的OnValueChanged处理程序有问题。我需要那里的代码来区分UI中的值集(通过各种绑定)和manager类中的值集。我曾希望DependencyPropertyChangedEventArgs会有某种来源,我可以用来区分这一点,但我没有看到类似的东西。思想?是否有某种方法可以设置WPF DependencyProperty而不触发其PropertyChanged处理程序?谢谢你抽出时间C# 从两个不同的源设置依赖项属性:需要不同的后处理吗,c#,wpf,dependency-properties,C#,Wpf,Dependency Properties,我有以下WPF代码。您可以在那里的评论中看到,我的OnValueChanged处理程序有问题。我需要那里的代码来区分UI中的值集(通过各种绑定)和manager类中的值集。我曾希望DependencyPropertyChangedEventArgs会有某种来源,我可以用来区分这一点,但我没有看到类似的东西。思想?是否有某种方法可以设置WPF DependencyProperty而不触发其PropertyChanged处理程序?谢谢你抽出时间 public class GaugeBaseContr
public class GaugeBaseControl : UserControl
{
protected readonly AssetModelManager Manager;
public GaugeBaseControl(AssetModelManager mgr)
{
Manager = mgr;
if(mgr != null)
mgr.TelemetryValueChanged += MgrOnTelemetryValueChanged; // coming on background thread
}
private void MgrOnTelemetryValueChanged(KeyValuePair<string, object> keyValuePair)
{
if(_localTelemetryId != keyValuePair.Key)
return;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
if (!Equals(Value, keyValuePair.Value))
Value = keyValuePair.Value;
}));
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var gbc = (GaugeBaseControl) d;
var id = gbc.TelemetryId;
if (!string.IsNullOrEmpty(id))
{
// this is the problem:
// I need to always set gbc.Manager[id] if this event was triggered from the UI (even when equal)
// however, if it was triggered by TelemetryValueChanged then we don't want to go around in circles
if (!Equals(gbc.Manager[id], e.NewValue))
gbc.Manager[id] = e.NewValue;
}
}
private string _localTelemetryId; // to save us a cross-thread check
private static void OnTelemetryIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var gbc = (GaugeBaseControl)d;
var tid = gbc.TelemetryId;
gbc._localTelemetryId = tid;
gbc.Value = string.IsNullOrEmpty(tid) ? null : gbc.Manager[tid];
}
public static readonly DependencyProperty TelmetryIdProperty = DependencyProperty.Register("TelemetryId", typeof(string), typeof(GaugeBaseControl), new PropertyMetadata(OnTelemetryIdChanged));
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(GaugeBaseControl), new PropertyMetadata(OnValueChanged));
public object Value
{
get { return GetValue(ValueProperty); }
set { SetValue(ValueProperty, value);}
}
public string TelemetryId
{
get { return (string)GetValue(TelmetryIdProperty); }
set { SetValue(TelmetryIdProperty, value); }
}
}
公共类GaugeBaseControl:UserControl
{
受保护的只读资产模型管理器;
公共计量器安全控制(资产模型经理)
{
经理=经理;
if(mgr!=null)
mgr.TelemetryValueChanged+=MgrOnTelemetryValueChanged;//正在后台线程中
}
私有void MgrOnTelemetryValueChanged(KeyValuePair KeyValuePair)
{
if(_localTelemetryId!=keyValuePair.Key)
返回;
Dispatcher.Invoke(DispatcherPriority.Normal,新操作(()=>
{
如果(!等于(值,keyValuePair.Value))
Value=keyValuePair.Value;
}));
}
私有静态void OnValueChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
变量gbc=(计量控制)d;
变量id=gbc.遥测id;
如果(!string.IsNullOrEmpty(id))
{
//这就是问题所在:
//如果此事件是从UI触发的(即使相等),我需要始终设置gbc.Manager[id]
//然而,如果它是由TelemetryValueChanged触发的,那么我们就不想兜圈子了
如果(!等于(gbc.Manager[id],e.NewValue))
gbc.Manager[id]=e.NewValue;
}
}
私有字符串_localTelemetryId;//用于保存跨线程检查
OnTelemetryIdChanged的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
变量gbc=(计量控制)d;
var tid=gbc.TelemetryId;
gbc._localTelemetryId=tid;
gbc.Value=string.IsNullOrEmpty(tid)?null:gbc.Manager[tid];
}
public static readonly dependencProperty TelmetryIdProperty=dependencProperty.Register(“遥测ID”、类型of(字符串)、类型of(GaugeBaseControl)、新属性元数据(OnTelemetryIdChanged));
public static readonly dependencProperty ValueProperty=dependencProperty.Register(“Value”、typeof(object)、typeof(GaugeBaseControl)、new PropertyMetadata(OnValueChanged));
公共对象价值
{
获取{return GetValue(ValueProperty);}
set{SetValue(ValueProperty,value);}
}
公共字符串遥测ID
{
获取{return(string)GetValue(TelmetryIdProperty);}
set{SetValue(TelmetryIdProperty,value);}
}
}
这似乎有点老土,但这是我在不改变架构的情况下能想到的最好的解决方案。在执行内部更新以停止往返时,可以停止侦听TelemetryValueChanged事件,如下所示:
internal void SetManagerIdInternal(string id, object value)
{
if(mgr != null)
{
mgr.TelemetryValueChanged -= MgrOnTelemetryValueChanged;
mgr[id] = value;
mgr.TelemetryValueChanged += MgrOnTelemetryValueChanged;
}
}
然后像这样使用它:
if (!Equals(gbc.Manager[id], e.NewValue))
SetManagerIdInternal(id, e.NewValue);
您也可以使用私有字段跳过工作,而不在MgrOnTelemetryValueChanged中注销/重新注册事件,这可能会更好地提高性能,但我还没有对其进行测试。除了使用标志外,我还使用了此取消订阅技巧。