Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从两个不同的源设置依赖项属性:需要不同的后处理吗_C#_Wpf_Dependency Properties - Fatal编程技术网

C# 从两个不同的源设置依赖项属性:需要不同的后处理吗

C# 从两个不同的源设置依赖项属性:需要不同的后处理吗,c#,wpf,dependency-properties,C#,Wpf,Dependency Properties,我有以下WPF代码。您可以在那里的评论中看到,我的OnValueChanged处理程序有问题。我需要那里的代码来区分UI中的值集(通过各种绑定)和manager类中的值集。我曾希望DependencyPropertyChangedEventArgs会有某种来源,我可以用来区分这一点,但我没有看到类似的东西。思想?是否有某种方法可以设置WPF DependencyProperty而不触发其PropertyChanged处理程序?谢谢你抽出时间 public class GaugeBaseContr

我有以下WPF代码。您可以在那里的评论中看到,我的OnValueChanged处理程序有问题。我需要那里的代码来区分UI中的值集(通过各种绑定)和manager类中的值集。我曾希望DependencyPropertyChangedEventArgs会有某种来源,我可以用来区分这一点,但我没有看到类似的东西。思想?是否有某种方法可以设置WPF DependencyProperty而不触发其PropertyChanged处理程序?谢谢你抽出时间

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中注销/重新注册事件,这可能会更好地提高性能,但我还没有对其进行测试。

除了使用标志外,我还使用了此取消订阅技巧。