WF ActivityValidator: checking if DependencyProperty has been boun

G

Guest

Scenario:
I have a custom activity that has a DependencyProperty. The property type is
a complex object (just an object with some properties, nothing fancy). When I
drag my custom activity onto a workflow I want to ensure the property is
bound to a field in the workflow.

Solution:
I’ve created a custom ActivityValidator to validate the activity. This works
fine for the other DependencyProperty’s that are simple types (e.g. strings).

Problem
My custom validator wont seem to work for the DependencyProperty that
contains a complex object.

Hers my custom validator

public class UpdatePaymentActivityValidator : ActivityValidator

{

public override ValidationErrorCollection Validate(ValidationManager
manager, object obj)

{

UpdatePaymentActivity updatePaymentActivity = obj as UpdatePaymentActivity;

ValidationErrorCollection validationErrors = new ValidationErrorCollection();

if (updatePaymentActivity == null)

{

throw new InvalidOperationException("Parameter obj is not of type : " +
typeof(UpdatePaymentActivity).ToString());

}

Activity parent = updatePaymentActivity.Parent;

if (parent != null)

{

// this validates OK

if (String.IsNullOrEmpty(updatePaymentActivity.Message))

{

validationErrors.Add(new ValidationError("Property Message is not set.", 1));

}

// this next line always fails because Payment is always null.

// Payment is a DependencyProperty on the activity and is a complex object

if (updatePaymentActivity.Payment == null)

{

validationErrors.Add(new ValidationError("Property Payment is not set.", 1));

}

}

return validationErrors;

}

}

The comment in the code indicates the like that always returns null. I can
understand that the value for Payment is going to be null, its not set until
runtime... but how do I check that its bound in the designer to a field in
the workflow? Perhaps by directly accessing something on the static
DependencyProperty of the activity?? Or do I have to create a validator for
the workflow that checks it? What am I missing here?
 
W

Wei Lu [MSFT]

Hello Keith,

I understand that you are using the Validator to valid the Activity in
Workflow design.

Based on my research, if you did not bound the Property to a field that
means the Property will be null and you could not compile the project and
the project will indicate a validation error.

So you do not need to concern about the unbound property because it will be
compiled.

Sincerely,

Wei Lu
Microsoft Online Community Support

==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

"if you did not bound the Property to a field that
means the Property will be null and you could not compile the project and
the project will indicate a validation error"

problem is I am binding the property but the validator still sees it as
null. Do this as a test:
create a workflow console application and add the following.

A customer class:
--------------------
public class Customer
{
private string _firstName;

public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}

private string _lastName;

public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
}

An activity:
--------------------
[ToolboxItem(typeof(ActivityToolboxItem))]
[Designer(typeof(ActivityDesigner), typeof(IDesigner))]
[ActivityValidator(typeof(WriteCustomerNameToConsoleActivityValidator))]
public class WriteCustomerNameToConsoleActivity : Activity
{
public static DependencyProperty CustomerProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("Customer",
typeof(Customer), typeof(WriteCustomerNameToConsoleActivity));

[Description("")]
[Category("")]
[Browsable(true)]

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Customer Customer
{
get
{
return
((Customer)(base.GetValue(WriteCustomerNameToConsoleActivity.CustomerProperty)));
}
set
{

base.SetValue(WriteCustomerNameToConsoleActivity.CustomerProperty, value);
}
}

public static DependencyProperty SimpleStringProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("SimpleString",
typeof(String), typeof(WriteCustomerNameToConsoleActivity));

[Description("")]
[Category("")]
[Browsable(true)]

[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public String SimpleString
{
get
{
return
((String)(base.GetValue(WriteCustomerNameToConsoleActivity.SimpleStringProperty)));
}
set
{

base.SetValue(WriteCustomerNameToConsoleActivity.SimpleStringProperty, value);
}
}

protected override ActivityExecutionStatus
Execute(ActivityExecutionContext executionContext)
{
Console.WriteLine("Customers name: '{0} {1}'",
Customer.FirstName, Customer.LastName);
Console.WriteLine("SimpleString : '{0}'", SimpleString);

return ActivityExecutionStatus.Closed;
}
}

An activity validator:
--------------------

public class WriteCustomerNameToConsoleActivityValidator : ActivityValidator
{
public override ValidationErrorCollection Validate(ValidationManager
manager, object obj)
{
WriteCustomerNameToConsoleActivity
writeCustomerNameToConsoleActivity = obj as
WriteCustomerNameToConsoleActivity;

ValidationErrorCollection validationErrors = new
ValidationErrorCollection();

if (writeCustomerNameToConsoleActivity == null)
{
throw new InvalidOperationException("Parameter obj is not of
type : " + typeof(WriteCustomerNameToConsoleActivity).ToString());
}

Activity parent = writeCustomerNameToConsoleActivity.Parent;

if (parent != null)
{
if (writeCustomerNameToConsoleActivity.Customer == null)
validationErrors.Add(new ValidationError("Property
Customer is not set.", 1));

if
(String.IsNullOrEmpty(writeCustomerNameToConsoleActivity.SimpleString))
validationErrors.Add(new ValidationError("Property
SimpleString is not set.", 1));
}

return validationErrors;
}
}

--------------------
A sequential workflow:

public sealed partial class Workflow1: SequentialWorkflowActivity
{
private Customer _customer;

public Customer Customer
{
get { return _customer; }
set { _customer = value; }
}

public Workflow1()
{
InitializeComponent();

_customer = new Customer();
_customer.FirstName = "Keith";
_customer.LastName = "Woods";
}

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
[System.Diagnostics.DebuggerNonUserCode]
private void InitializeComponent()
{
this.CanModifyActivities = true;
this.writeCustomerNameToConsoleActivity1 = new
WorkflowConsoleApplication5.WriteCustomerNameToConsoleActivity();
//
// writeCustomerNameToConsoleActivity1
//
this.writeCustomerNameToConsoleActivity1.Name =
"writeCustomerNameToConsoleActivity1";
//
// Workflow1
//
this.Activities.Add(this.writeCustomerNameToConsoleActivity1);
this.Name = "Workflow1";
this.CanModifyActivities = false;

}

private WriteCustomerNameToConsoleActivity
writeCustomerNameToConsoleActivity1;
}

Try compile it, you should get 2 errors because you have not bound the
activities customer and SimpleString properties. So in the workflow designer
for the above workflow click on the activity and select proeprties. Now add a
value for the SimpleString. Try compile agains, now only 1 error. Now bind
the activites customer property to the Customer property that hands of the
workflow and compile again. The validator still sees the customer as null.
Like I was mentioning before I can understand that the value for Payment is
going to be null, its not set until runtime... but how do I check that its
bound in the designer to a field in the workflow?
 
W

Wei Lu [MSFT]

Hello Keith,

I would like to know if you assign your propertys to a value in the code,
could you compile the project?

Sincerely,

Wei Lu
Microsoft Online Community Support

==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

I would like to know if you assign your propertys to a value in the code,

What exactly do you mean? The property 'Customer' in the example before gets
assigned at runtime. In my example that happens in the workflow constructor:

public Workflow1()
{
InitializeComponent();

_customer = new Customer();
_customer.FirstName = "Keith";
_customer.LastName = "Woods";
}

could you compile the project?
No because even thought I've bound the Customer property on the activity to
the Custom property on the workflow the customer is still set to null at the
time the activity validates:

if (writeCustomerNameToConsoleActivity.Customer == null)
validationErrors.Add(new ValidationError("Property
Customer is not set.", 1));
 
W

Wei Lu [MSFT]

Hello Keith,

I did reproduce this issue.

I am consulting internally for some advice. I appreciate your patience.

Sincerely,

Wei Lu
Microsoft Online Community Support

==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Wei Lu [MSFT]

Hello Keith,

I found that the main cause of this issue is that the DependcyProperty
could not have a default value for the reference type data. So we could not
assign a default value for the class. Thus, the dafult value for a class is
null so whenever you compile the project, the validator will recognize that
the property is null and so raise the error.

I found that you only use the class like a structure. So I thought that the
workaround is that you change your class Customer to be a structure. Since
struture in .NET is value type, so we could initialize the instance. Then,
in the workflow, you could bound the field to the property.

Here are some sample code:

using System;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;

namespace WFWorkShop
{
public struct PersonalAmount
{
public int Amount;
public string Name;

public PersonalAmount(int intAmount, string strName)
{
//Constructor, initialize the structure.

Amount = intAmount;
Name = strName;
}
}

[ActivityValidator(typeof(SimpleValidator))]
public partial class Simple : Activity
{

static PersonalAmount pAmount = new PersonalAmount(50,"");


public static readonly DependencyProperty PAmountProperty =
DependencyProperty.Register("PAmount",
typeof(PersonalAmount),
typeof(Simple), new PropertyMetadata(pAmount) //Set the default
value for the PAmount
);

public PersonalAmount PAmount
{
get { return (PersonalAmount)base.GetValue(PAmountProperty); }
set { base.SetValue(PAmountProperty, value); }
}
}

public class SimpleValidator : ActivityValidator
{
public override ValidationErrorCollection Validate(
ValidationManager manager, object obj)
{
ValidationErrorCollection errors =
base.Validate(manager, obj);

Simple simple = obj as Simple;

if (simple.PAmount.Amount > 100 || simple.PAmount.Amount < 50)
{
ValidationError error = new ValidationError(
"Simple.Amount must be between 50 and 100", 7000);
errors.Add(error);
}


return errors;
}
}
}

Hope this helps!

Sincerely,

Wei Lu
Microsoft Online Community Support

==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Wei Lu [MSFT]

Hi ,

How is everything going? Please feel free to let me know if you need any
assistance.

Sincerely,

Wei Lu
Microsoft Online Community Support

==================================================

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top