2

这应该很容易,但我无法弄清楚。当我的自定义活动的某些属性发生变化时(例如,通过在 WF 设计器的属性网格中更改它),我想动态更新 DisplayName。我在属性设置器代码中这样做:

public sealed class TarpSpecItem : Activity, ITarpSpecItem, INotifyPropertyChanged
{
...
    public DocumentationType Type
    {
        get { return _type; }
        set { _type = value;
            DisplayName = "<" + value.ToString() + ">";
            OnPropertyChanged("DisplayName");
            OnPropertyChanged("Type");
        }
    }

该活动实现 INotifyPropertyChanged。然而,DisplayName 在设计器表面上并没有改变。我错过了什么?


威尔的回答是正确的。我将设计器 *.xaml.cs 的更新代码粘贴到此处作为单独的答案以具有正确的格式(不可能作为评论)。这段代码编译并完成了任务。

    protected override void OnModelItemChanged(object newItem)
    {
        ModelItem modelItem = newItem as ModelItem;
        if (modelItem != null)
            modelItem.PropertyChanged += this.ModelItemPropertyChangedHandler;
        base.OnModelItemChanged(newItem);
    }

    private void ModelItemPropertyChangedHandler(object sender, PropertyChangedEventArgs e)
    {
        if (!e.PropertyName.Equals("Type", StringComparison.OrdinalIgnoreCase))
            return;
        ModelItem.Properties["DisplayName"].SetValue("<" + ModelItem.Properties["Type"].Value +">");
    }

将活动包装在模型项中并没有使解决方案显而易见,是吗?很难看到发生了什么,但它确实有效。干得好,威尔!

4

1 回答 1

4

Activity被包裹在一个 中ModelItem,它处理Activity 和设计表面之间的所有通知服务。

当最初包装在设计器中时,ModelItem不会检查您Activity是否提供了一些属性更改通知方法(INPC、自定义TypeDescriptor等)或其他接口(即,我在这里IDataErrorInfo有一个连接)。

所以,本质上,你不能做你试图在这里完成的事情。在 Activity 中,您无法通过包装 ModelItem 发回更改通知。无论如何,你真的不应该这样做。

在设计器中,状态更改应该通过ModelItem,因为它需要保持其状态与被包装的Activity. 如果它的状态和包装实例的状态不一致,您将不会在设计器中看到正确的信息。

// we're doing this in the designer
var activity = ModelItem.GetCurrentValue() as MyActivity; 
activity.DisplayName = "You won't ever see this in the design surface!";

相反,您必须通过ModelItem

// again, in the designer code
ModelItem.Properties["DisplayName"].Value = "You will see this change!";

那么,解决方案是什么?唯一真正的解决方案是确保您Activities在状态发生变化时处于被动状态! 属性值更改不应触发任何事情

相反,将这样的代码移动到设计器中!

override OnModelItemChanged(object obj)
{
    // live dangerously!
    var mi = obj as ModelItem;
    mi.PropertyChanged += OnPropertyChanged;
}

void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(!e.PropertyName.Equals("Type", StringComparison.OrdinalIgnoreCase))
        return;
    ModelItem.Properties["DisplayName"].Value = 
        "<" + 
        ModelItem.Properties["Type"].GetCurrentValue().ToString() + 
        ">";
}

当然,你不能只是复制粘贴这个。它可能有一些错误。但它让你知道你必须做什么。

于 2013-04-09T20:53:39.020 回答