As we build more advanced test steps that support multiple operations and use EnabledIf attributes to decide what the user sees in the Editor, the current BasicMixin example’s builder code displays all members and does not filter out members that are not enabled in the UI.
Can a builder code filter out non-visible members, and if so, what would such code look like?
public class EmbeddingClassMixin {
// show the setting if its enabled by the SomeSettingVisible property.
[EnabledIf(nameof(SomeSettingVisible), true, HideIfDisabled = true)]
public string SomeSetting{get;set;} = "123";
// this could be calculated with a complex expression.
// In that case it would only have a getter.
public bool SomeSettingVisible{get;set;}
Thanks for responding Rolf. My original post was not clear, sorry about that. To be more specific, if I am creating a custom Limits mixin, and the step the mixin is being added uses EnableIf attributes, how can the mixin determine what members in the step are visible or not due to its use of EnableIf attributes?
One way is to inherit from the MixinMemberData class and then override GetValue/SetValue. This will allow you to get information about the target object directly. You then need to use reflection to get properties and check if they are enabled or not. You can use
bool EnabledIfAttribute.IsEnabled(member, object, out dependentProperty, out bool hidden); ```
To get the information you are looking for once you have the member you are interested in.
Unfortunely I was not able to follow your guidance. Not sure what should inherit from MixinMemberData. When applied to my my FixinBuilder or my Mixin there complaints about conflicting with ValidatingObject. Below is my Initialize method that gathers the member list, but its call to EnabledIfAttribute() seems to return false when I would expect it to return true. The log include stuff like:
“21:26:27.016 EnabledIf Could not find property ‘ReadMultiple’ on ‘OpenTap.DynamicMemberTypeDataProvider+TestStepTypeData’. EnabledIfAttribute can only refer to properties of the same class as the property it is decorating.”
public void Initialize(ITypeData targetType)
{
List<string> memberNames = new List<string>();
List<string> outputMemberNames = new List<string>();
var members = targetType.GetMembers();
foreach (var member in members)
{
string typeDescriptorName = member.TypeDescriptor.Name;
string typeName = MixinUtils.GetBasicTypeName(typeDescriptorName);
//Filter out members that are not simple data types properties that are of value to compare against
if (!MixinUtils.IsBuiltInTestStepMember(member.Name) &&
!MixinUtils.IsPluginMember(member.Name) &&
!MixinUtils.IsCustomType(typeName) &&
!MixinUtils.IsArrayType(typeName) &&
!MixinUtils.IsCollectionsGenericListType(typeName))
{
bool hasEnableIfAttribute = member.HasAttribute<EnabledIfAttribute>();
bool enabled = !hasEnableIfAttribute || EnabledIfAttribute.IsEnabled(member, targetType);
if (!enabled)
continue;
string memberName = member.Name + " (" + typeName + ")";
memberNames.Add(memberName);
if (member.HasAttribute<OutputAttribute>())
outputMemberNames.Add(memberName);
}
}
memberNames.Sort(StringComparer.OrdinalIgnoreCase);
AllMembers = memberNames.ToArray();
outputMemberNames.Sort(StringComparer.OrdinalIgnoreCase);
OutputMembers = outputMemberNames.ToArray();
Members = (ShowOutputsOnly) ? OutputMembers : AllMembers;
if (string.IsNullOrWhiteSpace(MemberDisplayName))
MemberDisplayName = (ShowOutputsOnly) ? OutputMembers.FirstOrDefault() ?? "" : AllMembers.FirstOrDefault() ?? "";
}
That is because at this point you cannot access to that information - As a general rule, when you setup the mixin you only have access to static information (not instance information), such as which members the target type has and what the attributes are.
At the moment, getting information about the target instance is not supported before the mixin is created.
That is what I thought, thanks for confirming. Bummer, seems that the Add Mixin UI operation should be able to share the instance instead of only static type information. Not sure if such an improvement could be done or whether that would break compatibility.
Just curious, you said “getting information about the target instance is not supported before the mixin is created.” Are you suggesting that the information is available after a mixin is created and if so, is there a way to update a member dropdown list in the mixin UI?
What I mean is that once the mixin is deployed it can access the object it is assigned to. So you can do what you want with the mixin, but not with the mixin builder.
The benefit of this API is that you can be sure that the mixin builder itself does not modify the target object without the user clicking OK first. However, as you experience now it is also less powerful than if it had that access.