none
Set the InArgument values of a CodeActivity<T> inside NativeActivity

    Question

  • Inside my Native Activity:

    //Operation holds the object of Add activity mentioned in the below code.
    public Activity Operation { get; set; }

    //I tried to set InArgument of Add activity using the below code inside native activity.
    Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) 5.01, null);
    Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>) 2.01, null);

    Simple Add Code Activity:

    public sealed class Add : CodeActivity<double>
    {
            public InArgument<double> Number1 { get; set; }
            public InArgument<double> Number2 { get; set; }
    
            protected override double Execute(CodeActivityContext context)
            {
               return (Number1.Get(context) * Number2.Get(context));
            }
    }

    With reference to above code: I get the below error at the following location: return (Number1.Get(context) + Number2.Get(context));

    The argument of type 'System.Double' cannot be used.  Make sure that it is declared on an activity.
    My requirement is to set the values of Number1,Number2 of Add activity inside native activity rather than at the designer.Is there any better way to do it?
    Friday, December 11, 2009 9:47 AM

Answers

  • OK, as I said in last reply, you can declare two internal variables and bind the variable to Operation arguments first in CacheMetadata() and then set variables value with the execution results of input before scheduling Operation activity in the callback. See updated code below, required changes are in bold

        public sealed class Sample : NativeActivity<double>
        {
            //User will drop two inputs
            public Collection<Activity> Input { get; set; }

            //User will drop addition,subtraction,operation based activities
            public Activity Operation { get; set; }

            public Activity Output { get; set; }

            private double[] _inputResult;

            int _count;

            private Variable<double> number1;
            private Variable<double> number2;

            public Sample()
                : base()
            {
                this.Input = new Collection<Activity>();
            }

            protected override void CacheMetadata(NativeActivityMetadata metadata)
            {          
                this.number1 = new Variable<double>();
                this.number2 = new Variable<double>();
                metadata.AddImplementationVariable(this.number1);
                metadata.AddImplementationVariable(this.number2);

                Operation.GetType().GetProperty("Number1").SetValue(Operation, new InArgument<double>(this.number1), null);
                Operation.GetType().GetProperty("Number2").SetValue(Operation, new InArgument<double>(this.number2), null);
                metadata.AddImplementationChild(Operation);

                foreach (Activity input in this.Input)
                {
                    metadata.AddChild(input);
                }

                metadata.AddChild(Output);
            }

            protected override void Execute(NativeActivityContext context)
            {
                this._inputResult = new double[Input.Count];
                this._count = 0;

                //Schedule and execute input activities
                for (int count = 0; count < this.Input.Count; count++)
                {
                    Activity<double> nextChild = (Activity<double>)Input[count];
                    context.ScheduleActivity<double>(nextChild, InputComplete);
                }
            }

            private void InputComplete(NativeActivityContext context, ActivityInstance instance, double result)
            {
                //Get the result of the input activities and store them in an array      
                _inputResult[this._count++] = result;

                if (this._count == this.Input.Count)
                {
                    //Schedule and execute operation activities like addition,subtraction,etc

                    /*Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) _inputResult[0], null);
                      Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>)_inputResult[1], null); */

                    this.number1.Set(context, _inputResult[0]);
                    this.number2.Set(context, _inputResult[1]);

                    context.ScheduleActivity<double>((Activity<double>)Operation, OperationComplete);
                }
            }

            private void OperationComplete(NativeActivityContext context, ActivityInstance instance, double result)
            {
                //Get the result from Operation and do compuatations........
                //MessageBox.Show(result.ToString);
            }
        }

    • Marked as answer by sans_india85 Monday, January 04, 2010 4:26 AM
    Monday, December 28, 2009 6:35 AM

All replies

  • The question was modified and simplified due to no responses.Please recheck the modified question.Please let me know if the question is not clear.
    Monday, December 14, 2009 9:41 AM
  • Where do you run the property setting code in the NativeActivity? In the Execute method or CachedMetadata? You need to set these properties in CachedMetadata and call base.CachedMetadata to get it work.
    Thursday, December 17, 2009 2:20 PM
  • Hi Congyu,

    Where do you run the property setting code in the NativeActivity? In the Execute method or CachedMetadata?

    //I tried to set InArgument of Add activity using the below code inside native activity.
    Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) number1Value, null);
    Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>) number2Value, null);

    I set the the values of the InArgument in the execute method.I need to set these values in the execute method because I get number1Value,number2Value on execution of an activity and its results are set to number1Value,number2Value.

    Is reflection the only way to set the InArgument values of an Activity inside NativeActivity at execute method.

    I will share the complete code if your not clear.

    Thanks,
    Sandeep.
    Monday, December 21, 2009 6:18 AM
  • I see. One option here is declaring two internal variables in your NativeActivity. Then bind Number1 and Number2 arguments to these two internal variables in CachedMetatData and also set execution results of number1Value and number2Value to these internal variables.

    Not sure whether this works for you, it not, please let me know more details, e.g. how does number1Value & number2Value come from?

    Thanks,
    Congyu

    Monday, December 21, 2009 11:30 AM
  • Thanks Congyu for your time.Here is the complete code.

    Native Activity:

    [Designer(typeof(SampleDesigner))]
    public sealed class Sample : NativeActivity<double>

       //User will drop two inputs
       public Collection<Activity> Input { get; set; }           
      
       //User will drop addition,subtraction,operation based activities
       public Activity Operation { get; set; }

       public Activity Output { get; set; }     
      
       private double[] _inputResult;   

       public Sample() : base()
       {
          this.Input = new Collection<Activity>(); 
       }

       protected override void CacheMetadata(NativeActivityMetadata metadata)
       {
          base.CacheMetadata(metadata); 
       }

       protected override void Execute(NativeActivityContext context)
       {
          this._inputResult = new double[Input.Count];
          this._count = 0;

          //Schedule and execute input activities
          for (int count = 0; count < this.Input.Count; count++ )
          {      
              Activity<double> nextChild = (Activity<double>)Input[count];
              context.ScheduleActivity<double>(nextChild, InputComplete);
          }
       }

      private void InputComplete(NativeActivityContext context, ActivityInstance instance, double result)
      {          
          //Get the result of the input activities and store them in an array      
          _inputResult[this._count++] = result;

          if (this._count == this.Input.Count)
          {        
             //Schedule and execute operation activities like addition,subtraction,etc 

             /*Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) _inputResult[0], null);
               Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>)_inputResult[1], null); */
                   
               Operation.GetType().GetProperty("Number1").SetValue(Operation, _inputResult[0], null);
               Operation.GetType().GetProperty("Number2").SetValue(Operation, _inputResult[1], null);
                  
               context.ScheduleActivity<double>((Activity<double>)Operation, OperationComplete);  
          }
      }

      private void OperationComplete(NativeActivityContext context,  ActivityInstance instance, double result)
      {   
         //Get the result from Operation and do compuatations........
        //MessageBox.Show(result.ToString);
      }
    }

    Not sure whether this works for you, it not, please let me know more details, e.g. how does number1Value & number2Value come from?

    Please check InputComplete method in the above code.This application works in a rehosted designer.

    Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) _inputResult[0], null);
    Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>)_inputResult[1], null);

    Iam able to to set InArgument values of an Operation using reflection. Please tell me if there is any better way

    But I get the error at "return (Number1.Get(context) * Number2.Get(context));" for the below code called The argument of type 'System.Double' cannot be used.  Make sure that it is declared on an activity.

    Simple Add Code Activity:
    public sealed class Add : CodeActivity<double>
    {
            public InArgument<double> Number1 { get; set; }
            public InArgument<double> Number2 { get; set; }

            protected override double Execute(CodeActivityContext  context)
            {
               return (Number1.Get(context) * Number2.Get(context));
            }
    }

    //Number1 and Number2 as public properties of a CodeActivity
    Operation.GetType().GetProperty("Number1").SetValue(Operation, _inputResult[0], null);
    Operation.GetType().GetProperty("Number2").SetValue(Operation, _inputResult[1], null);

    Since,Iam unable to assign values using InArgument's. For a while,Iam using public properties. 


    Please let me know if its not clear!
    Monday, December 21, 2009 1:19 PM
  • OK, as I said in last reply, you can declare two internal variables and bind the variable to Operation arguments first in CacheMetadata() and then set variables value with the execution results of input before scheduling Operation activity in the callback. See updated code below, required changes are in bold

        public sealed class Sample : NativeActivity<double>
        {
            //User will drop two inputs
            public Collection<Activity> Input { get; set; }

            //User will drop addition,subtraction,operation based activities
            public Activity Operation { get; set; }

            public Activity Output { get; set; }

            private double[] _inputResult;

            int _count;

            private Variable<double> number1;
            private Variable<double> number2;

            public Sample()
                : base()
            {
                this.Input = new Collection<Activity>();
            }

            protected override void CacheMetadata(NativeActivityMetadata metadata)
            {          
                this.number1 = new Variable<double>();
                this.number2 = new Variable<double>();
                metadata.AddImplementationVariable(this.number1);
                metadata.AddImplementationVariable(this.number2);

                Operation.GetType().GetProperty("Number1").SetValue(Operation, new InArgument<double>(this.number1), null);
                Operation.GetType().GetProperty("Number2").SetValue(Operation, new InArgument<double>(this.number2), null);
                metadata.AddImplementationChild(Operation);

                foreach (Activity input in this.Input)
                {
                    metadata.AddChild(input);
                }

                metadata.AddChild(Output);
            }

            protected override void Execute(NativeActivityContext context)
            {
                this._inputResult = new double[Input.Count];
                this._count = 0;

                //Schedule and execute input activities
                for (int count = 0; count < this.Input.Count; count++)
                {
                    Activity<double> nextChild = (Activity<double>)Input[count];
                    context.ScheduleActivity<double>(nextChild, InputComplete);
                }
            }

            private void InputComplete(NativeActivityContext context, ActivityInstance instance, double result)
            {
                //Get the result of the input activities and store them in an array      
                _inputResult[this._count++] = result;

                if (this._count == this.Input.Count)
                {
                    //Schedule and execute operation activities like addition,subtraction,etc

                    /*Operation.GetType().GetProperty("Number1").SetValue(Operation, (InArgument<double>) _inputResult[0], null);
                      Operation.GetType().GetProperty("Number2").SetValue(Operation, (InArgument<double>)_inputResult[1], null); */

                    this.number1.Set(context, _inputResult[0]);
                    this.number2.Set(context, _inputResult[1]);

                    context.ScheduleActivity<double>((Activity<double>)Operation, OperationComplete);
                }
            }

            private void OperationComplete(NativeActivityContext context, ActivityInstance instance, double result)
            {
                //Get the result from Operation and do compuatations........
                //MessageBox.Show(result.ToString);
            }
        }

    • Marked as answer by sans_india85 Monday, January 04, 2010 4:26 AM
    Monday, December 28, 2009 6:35 AM
  • Thanks Congyu!

    Monday, January 04, 2010 4:26 AM