Home » .Net FrameworkRSS

Customer Activity Designer Problem - "Could not generate view for VisualBasicValue`1"

I'm reading Bruce Bukovics Pro WF4 book and in chapter 16 - Advanced Customer Activites, he details emulating a Sequence activity along with a custom designer. When I drop the custom activity into a new xaml activity, I'm getting all sorts of wierdness. The custom sequence activity has a condition property that determines whether to schedule each child activity contained within. Once I set a value in the ExpressionTextBox for the activity, Visual Studio starts showing in red "Could not generate view for VisualBasicValue`1" along with this error showing up in my error window:

The activity 'VisualBasicValue<Boolean>' cannot be referenced by activity 'MySequence' because the latter is not in another activity's implementation.  An activity can only be referenced by the implementation of an activity which specifies that activity as a child or import.  Activity 'VisualBasicValue<Boolean>' is declared by activity 'MySequence'.

Here is the source for the activity itself:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace ActivityLibrary
{
	[Designer(typeof(ActivityLibrary.Design.MySequenceDesigner))]
	publicsealedclass MySequence : NativeActivity
	{
		[Browsable(false)]
		public Collection<Activity> Activities { get; set; }

		[RequiredArgument]
		public Activity<bool> Condition { get; set; }

		Variable<int> activityIndex = new Variable<int>("ActivityIndex", 0);

		public MySequence()
		{
			Activities = new Collection<Activity>();
		}

		protectedoverridevoid CacheMetadata(NativeActivityMetadata metadata)
		{
			Console.WriteLine("CacheMetadata");
			metadata.SetChildrenCollection(Activities);
			metadata.AddChild(Condition);
			metadata.AddImplementationVariable(activityIndex);
		}

		protectedoverridevoid Execute(NativeActivityContext context)
		{
			if (Condition != null)
			{
				Console.WriteLine("Executed Scheduled Condition");
				context.ScheduleActivity<bool>(Condition, OnConditionComplete);
			}
		}

		void OnConditionComplete(NativeActivityContext context, ActivityInstance completedInstance, bool result)
		{
			Console.WriteLine("OnConditionComplete: State:{0}, IsCompleted:{1}: Result:{2}", completedInstance.State, completedInstance.IsCompleted, result);
			if (!context.IsCancellationRequested && result)
			{
				int index = activityIndex.Get(context);
				if (index < Activities.Count)
				{
					Console.WriteLine("OnConditionComplete Scheduled Activity: {0}", Activities[index].DisplayName);
					context.ScheduleActivity(Activities[index], OnComplete, OnFaulted);
					index++;
					activityIndex.Set(context, index);
				}
			}
		}

		void OnComplete(NativeActivityContext context, ActivityInstance completedInstance)
		{
			Console.WriteLine("OnComplete: State:{0}, IsCompleted:{1}", completedInstance.State, completedInstance.IsCompleted);

			if (!context.IsCancellationRequested)
			{
				if (Condition != null)
				{
					Console.WriteLine("OnComplete Scheduled Condition");
					context.ScheduleActivity<bool>(Condition, OnConditionComplete, OnFaulted);
				}
			}
		}

		void OnFaulted(NativeActivityFaultContext context, Exception propagatedException, ActivityInstance propagatedFrom)
		{
			Console.WriteLine("OnFaulted: {0}", propagatedException.Message);
		}

		protectedoverridevoid Cancel(NativeActivityContext context)
		{
			Console.WriteLine("Cancel");
			if (context.IsCancellationRequested)
			{
				Console.WriteLine("IsCancellationRequested");
				context.CancelChildren();
			}
		}

		protectedoverridevoid Abort(NativeActivityAbortContext context)
		{
			base.Abort(context);
			Console.WriteLine("Abort Reason: {0}", context.Reason.Message);
		}
	}
}

And here is the xaml for the designer:

 

<sap:ActivityDesignerx:Class="ActivityLibrary.Design.MySequenceDesigner"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:s="clr-namespace:System;assembly=mscorlib"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"xmlns:mva="clr-namespace:Microsoft.VisualBasic.Activities;assembly=System.Activities"Collapsible="True"><sap:ActivityDesigner.Resources><DataTemplatex:Key="ShowAsCollapsed"><TextBlockForeground="Gray"><TextBlock.Text><MultiBindingStringFormat="Expand for {0} Activities"><BindingPath="ModelItem.Activities.Count"/></MultiBinding></TextBlock.Text></TextBlock></DataTemplate><DataTemplatex:Key="ShowAsExpanded"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><RowDefinition/></Grid.RowDefinitions><TextBlockText="Condition"Grid.Row="0"Grid.Column="0"HorizontalAlignment="Left"VerticalAlignment="Center"/><sapv:ExpressionTextBoxHintText="Enter a condition"Grid.Row="0"Grid.Column="1"MaxWidth="150"MinWidth="150"Margin="5"OwnerActivity="{Binding Path=ModelItem}"ExpressionType="{x:Type TypeName=s:Boolean}"Expression="{Binding Path=ModelItem.Condition, Mode=TwoWay}"/><sap:WorkflowItemsPresenterGrid.Row="1"Grid.Column="0"Grid.ColumnSpan="2"HintText="Drop activities here"Margin="5"MinHeight="100"Items="{Binding Path=ModelItem.Activities, Mode=TwoWay}"><sap:WorkflowItemsPresenter.SpacerTemplate><DataTemplate><RectangleWidth="140"Height="3"Fill="LightGray"Margin="7"/></DataTemplate></sap:WorkflowItemsPresenter.SpacerTemplate><sap:WorkflowItemsPresenter.ItemsPanel><ItemsPanelTemplate><StackPanelOrientation="Vertical"/></ItemsPanelTemplate></sap:WorkflowItemsPresenter.ItemsPanel></sap:WorkflowItemsPresenter></Grid></DataTemplate><Stylex:Key="StyleWithCollapse"TargetType="{x:Type ContentPresenter}"><SetterProperty="ContentTemplate"Value="{DynamicResource ShowAsExpanded}"/><Style.Triggers><DataTriggerBinding="{Binding Path=ShowExpanded}"Value="False"><SetterProperty="ContentTemplate"Value="{DynamicResource ShowAsCollapsed}"/></DataTrigger></Style.Triggers></Style></sap:ActivityDesigner.Resources><Grid><ContentPresenterStyle="{DynamicResource StyleWithCollapse}"Content="{Binding}"/></Grid></sap:ActivityDesigner>
Any advice or assistance on why this is happening would be greatly appreciated!
 

7 Answers Found

 

Answer 1

Hello James,

I think your problem  comes from the following lines:

  protectedoverridevoid CacheMetadata(NativeActivityMetadata metadata)
{
Console.WriteLine("CacheMetadata");
metadata.SetChildrenCollection(Activities);
metadata.AddChild(Condition);
metadata.AddImplementationVariable(activityIndex);
}

AddChild should be AddImplementationChild.

Thanks,

Eric

 

Answer 2

It's not an implementation child  though since it can be set  at design  time right?
 

Answer 3

My mistake.  You are entirely correct.  I looked at the error  message and for some reason assumed that condition  was internal to your activity. Apologies.

What you need to do is simply add the Condition activity  to your ChildrenCollection (In this case, it's your Activities collection) and you should be good to go.

-Eric

 

Answer 4

That doesn't work though because foreach each activity  in the Activities collection, before I schedule  each of them to execute (via ScheduleActivity), I want to execute the Condition property  (returning a bool) to determine whether or not I should execute the next Activity in the Activities collection.

 

Answer 5

Ah. apologies for the confusing previous post.

First a code sample of what (hopefully) is the right cache metadata  code:

        protected  override void  CacheMetadata(NativeActivityMetadata metadata)
        {
            Console.WriteLine("CacheMetadata");
            this.Activities.ToList().ForEach(a => metadata.AddChild(a));
            metadata.AddChild(Condition);
            metadata.AddImplementationVariable(activityIndex);
        }

Under the covers, SetChildrenCollection takes the collection  you pass in and sets the collection of to what you pass in by reference.  Afterwards, calling AddChild adds the collection to the the ChildrenCollection (and thus to your Activities collection as well).  As cache metadata is called multiple times, this results in multiple entries for your condition  activity, which in turn generates the error  message you saw. 

The above code should work for your scenario.

Also, I'd like to apologize again for the confusion in my previous posts.  Hopefully this will solve your problem.

-Eric

 

Answer 6

Eric,

Thanks, I think I follow. If this is the case though, why would anyone ever want to call SetChildrenCollection?

 

Answer 7

SetChildrenCollection works well in the a case like Sequence activity, where the set  of all children is really contained  in an existing collection, and it makes more sense to reuse that collection  than create a new one (via AddChild implicitly, or explicitly). Otherwise it's simpler just to use AddChild.

Tim

 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter