e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
371 lines
12 KiB
C#
371 lines
12 KiB
C#
//----------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//----------------------------------------------------------------
|
|
|
|
namespace System.Activities
|
|
{
|
|
using System.Activities.Debugger;
|
|
using System.Activities.Validation;
|
|
using System.Activities.XamlIntegration;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Runtime;
|
|
using System.Windows.Markup;
|
|
using System.Xaml;
|
|
|
|
[ContentProperty("Implementation")]
|
|
public sealed class ActivityBuilder : IDebuggableWorkflowTree
|
|
{
|
|
// define attached properties that will identify PropertyReferenceExtension-based
|
|
// object properties
|
|
static AttachableMemberIdentifier propertyReferencePropertyID = new AttachableMemberIdentifier(typeof(ActivityBuilder), "PropertyReference");
|
|
static AttachableMemberIdentifier propertyReferencesPropertyID = new AttachableMemberIdentifier(typeof(ActivityBuilder), "PropertyReferences");
|
|
|
|
KeyedCollection<string, DynamicActivityProperty> properties;
|
|
Collection<Constraint> constraints;
|
|
Collection<Attribute> attributes;
|
|
|
|
public ActivityBuilder()
|
|
{
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[DependsOn("Name")]
|
|
public Collection<Attribute> Attributes
|
|
{
|
|
get
|
|
{
|
|
if (this.attributes == null)
|
|
{
|
|
this.attributes = new Collection<Attribute>();
|
|
}
|
|
return this.attributes;
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DependsOn("Attributes")]
|
|
public KeyedCollection<string, DynamicActivityProperty> Properties
|
|
{
|
|
get
|
|
{
|
|
if (this.properties == null)
|
|
{
|
|
this.properties = new ActivityPropertyCollection();
|
|
}
|
|
return this.properties;
|
|
}
|
|
}
|
|
|
|
|
|
[DependsOn("Properties")]
|
|
[Browsable(false)]
|
|
public Collection<Constraint> Constraints
|
|
{
|
|
get
|
|
{
|
|
if (this.constraints == null)
|
|
{
|
|
this.constraints = new Collection<Constraint>();
|
|
}
|
|
return this.constraints;
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ImplementationVersionConverter))]
|
|
[DefaultValue(null)]
|
|
[DependsOn("Name")]
|
|
public Version ImplementationVersion
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
[Browsable(false)]
|
|
[DependsOn("Constraints")]
|
|
public Activity Implementation
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
// Back-compat workaround: PropertyReference shipped in 4.0. PropertyReferences is new in 4.5.
|
|
//
|
|
// Requirements:
|
|
// - Runtime compat: Get/SetPropertyReference needs to continue to work, both when set programatically
|
|
// and when loading a doc which contains only one PropertyReference on an object.
|
|
// - Serialization compat: If only one PropertyReference was set, we shouldn't serialize PropertyReferences.
|
|
// (Only affects when ActivityBuilder is used directly with XamlServices, since ActivityXamlServices
|
|
// will convert ActivityPropertyReference to PropertyReferenceExtension.)
|
|
// - Usability: To avoid the designer needing to support two separate access methods, we want
|
|
// the value from SetPropertyReference to also appear in the PropertyReferences collection.
|
|
|
|
// <ActivityBuilder.PropertyReference>activity property name</ActivityBuilder.PropertyReference>
|
|
public static ActivityPropertyReference GetPropertyReference(object target)
|
|
{
|
|
return GetPropertyReferenceCollection(target).SingleItem;
|
|
}
|
|
|
|
// <ActivityBuilder.PropertyReference>activity property name</ActivityBuilder.PropertyReference>
|
|
public static void SetPropertyReference(object target, ActivityPropertyReference value)
|
|
{
|
|
GetPropertyReferenceCollection(target).SingleItem = value;
|
|
}
|
|
|
|
public static IList<ActivityPropertyReference> GetPropertyReferences(object target)
|
|
{
|
|
return GetPropertyReferenceCollection(target);
|
|
}
|
|
|
|
public static bool ShouldSerializePropertyReference(object target)
|
|
{
|
|
PropertyReferenceCollection propertyReferences = GetPropertyReferenceCollection(target);
|
|
return propertyReferences.Count == 1 && propertyReferences.SingleItem != null;
|
|
}
|
|
|
|
public static bool ShouldSerializePropertyReferences(object target)
|
|
{
|
|
PropertyReferenceCollection propertyReferences = GetPropertyReferenceCollection(target);
|
|
return propertyReferences.Count > 1 || propertyReferences.SingleItem == null;
|
|
}
|
|
|
|
internal static bool HasPropertyReferences(object target)
|
|
{
|
|
PropertyReferenceCollection propertyReferences;
|
|
if (AttachablePropertyServices.TryGetProperty(target, propertyReferencesPropertyID, out propertyReferences))
|
|
{
|
|
return propertyReferences.Count > 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static PropertyReferenceCollection GetPropertyReferenceCollection(object target)
|
|
{
|
|
PropertyReferenceCollection propertyReferences;
|
|
if (!AttachablePropertyServices.TryGetProperty(target, propertyReferencesPropertyID, out propertyReferences))
|
|
{
|
|
propertyReferences = new PropertyReferenceCollection(target);
|
|
AttachablePropertyServices.SetProperty(target, propertyReferencesPropertyID, propertyReferences);
|
|
}
|
|
return propertyReferences;
|
|
|
|
}
|
|
|
|
Activity IDebuggableWorkflowTree.GetWorkflowRoot()
|
|
{
|
|
return this.Implementation;
|
|
}
|
|
|
|
internal static KeyedCollection<string, DynamicActivityProperty> CreateActivityPropertyCollection()
|
|
{
|
|
return new ActivityPropertyCollection();
|
|
}
|
|
|
|
class ActivityPropertyCollection : KeyedCollection<string, DynamicActivityProperty>
|
|
{
|
|
protected override string GetKeyForItem(DynamicActivityProperty item)
|
|
{
|
|
return item.Name;
|
|
}
|
|
}
|
|
|
|
// See back-compat requirements in comment above. Design is:
|
|
// - First value added to collection when it is empty becomes the single PropertyReference value
|
|
// - If the single value is removed, then PropertyReference AP is removed
|
|
// - If PropertyReference AP is set to null, we remove the single value.
|
|
// - If PropertyReference is set to non-null, we replace the existing single value if there
|
|
// is one, or else add the new value to the collection.
|
|
class PropertyReferenceCollection : Collection<ActivityPropertyReference>
|
|
{
|
|
WeakReference targetObject;
|
|
int singleItemIndex = -1;
|
|
|
|
public PropertyReferenceCollection(object target)
|
|
{
|
|
this.targetObject = new WeakReference(target);
|
|
}
|
|
|
|
public ActivityPropertyReference SingleItem
|
|
{
|
|
get
|
|
{
|
|
return this.singleItemIndex >= 0 ? this[this.singleItemIndex] : null;
|
|
}
|
|
set
|
|
{
|
|
if (this.singleItemIndex >= 0)
|
|
{
|
|
if (value != null)
|
|
{
|
|
SetItem(this.singleItemIndex, value);
|
|
}
|
|
else
|
|
{
|
|
RemoveItem(this.singleItemIndex);
|
|
}
|
|
}
|
|
else if (value != null)
|
|
{
|
|
Add(value);
|
|
if (Count > 1)
|
|
{
|
|
this.singleItemIndex = Count - 1;
|
|
UpdateAttachedProperty();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void ClearItems()
|
|
{
|
|
this.singleItemIndex = -1;
|
|
UpdateAttachedProperty();
|
|
}
|
|
|
|
protected override void InsertItem(int index, ActivityPropertyReference item)
|
|
{
|
|
base.InsertItem(index, item);
|
|
if (index <= this.singleItemIndex)
|
|
{
|
|
this.singleItemIndex++;
|
|
}
|
|
else if (Count == 1)
|
|
{
|
|
Fx.Assert(this.singleItemIndex < 0, "How did we have an index if we were empty?");
|
|
this.singleItemIndex = 0;
|
|
UpdateAttachedProperty();
|
|
}
|
|
}
|
|
|
|
protected override void RemoveItem(int index)
|
|
{
|
|
base.RemoveItem(index);
|
|
if (index < this.singleItemIndex)
|
|
{
|
|
this.singleItemIndex--;
|
|
}
|
|
else if (index == this.singleItemIndex)
|
|
{
|
|
this.singleItemIndex = -1;
|
|
UpdateAttachedProperty();
|
|
}
|
|
}
|
|
|
|
protected override void SetItem(int index, ActivityPropertyReference item)
|
|
{
|
|
base.SetItem(index, item);
|
|
if (index == this.singleItemIndex)
|
|
{
|
|
UpdateAttachedProperty();
|
|
}
|
|
}
|
|
|
|
void UpdateAttachedProperty()
|
|
{
|
|
object target = this.targetObject.Target;
|
|
if (target != null)
|
|
{
|
|
if (this.singleItemIndex >= 0)
|
|
{
|
|
AttachablePropertyServices.SetProperty(target, propertyReferencePropertyID, this[this.singleItemIndex]);
|
|
}
|
|
else
|
|
{
|
|
AttachablePropertyServices.RemoveProperty(target, propertyReferencePropertyID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[ContentProperty("Implementation")]
|
|
public sealed class ActivityBuilder<TResult> : IDebuggableWorkflowTree
|
|
{
|
|
KeyedCollection<string, DynamicActivityProperty> properties;
|
|
Collection<Constraint> constraints;
|
|
Collection<Attribute> attributes;
|
|
|
|
public ActivityBuilder()
|
|
{
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[DependsOn("Name")]
|
|
public Collection<Attribute> Attributes
|
|
{
|
|
get
|
|
{
|
|
if (this.attributes == null)
|
|
{
|
|
this.attributes = new Collection<Attribute>();
|
|
}
|
|
return this.attributes;
|
|
}
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DependsOn("Attributes")]
|
|
public KeyedCollection<string, DynamicActivityProperty> Properties
|
|
{
|
|
get
|
|
{
|
|
if (this.properties == null)
|
|
{
|
|
this.properties = ActivityBuilder.CreateActivityPropertyCollection();
|
|
}
|
|
return this.properties;
|
|
}
|
|
}
|
|
|
|
[DependsOn("Properties")]
|
|
[Browsable(false)]
|
|
public Collection<Constraint> Constraints
|
|
{
|
|
get
|
|
{
|
|
if (this.constraints == null)
|
|
{
|
|
this.constraints = new Collection<Constraint>();
|
|
}
|
|
return this.constraints;
|
|
}
|
|
}
|
|
|
|
[TypeConverter(typeof(ImplementationVersionConverter))]
|
|
[DefaultValue(null)]
|
|
[DependsOn("Name")]
|
|
public Version ImplementationVersion
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[DefaultValue(null)]
|
|
[Browsable(false)]
|
|
[DependsOn("Constraints")]
|
|
public Activity Implementation
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
Activity IDebuggableWorkflowTree.GetWorkflowRoot()
|
|
{
|
|
return this.Implementation;
|
|
}
|
|
}
|
|
|
|
}
|