Setting a dependency property's default value at design time in a Windows Workflow Foundation Custom Activity - workflow

I'm implementing a Custom Workflow and Activities to be reused in multiple projects and trying to get them to be as easy to use as possible. In this workflow I have a Property whose name is 'UserID' which I'd like to bind to a dependencyproperty in one of my activities. I can currently bind it at design time searching explicitly for the property each time I add one of these activities to the workflow, but I'd like for this activity to be binded automatically.
As far as i know (correct me if I'm wrong), to bind a dependency property at design time I need to specify a string of the form "Activity=NameOfWorkflow, Path=UserID" to the DefaultBindingProperty metadata tag, and I'd like the name of the workflow to be completed in some way. Any way of doing this?
Thanks

I finally managed to achieve this by attaching an ActivityToolboxItem to the Activity, and overriding a method in it that creates the instance shown in the designer. I used an ActivityBind object to bind the dependencyproperty to the workflow's property. To get the instance of the workflow, I just searched for an ancestor to my activity by calling act.Parent until the activity had no parent (and thus was the StateMachineWorkflowActivity itself)

Related

Number of converter instance for binding in UWP

How many instance does binding creates internally for converters.
<Image x:Uid="DisplayedImageUrl" Style="{StaticResource ImageStyle}"
Source="{Binding DisplayedImageURL, Converter={StaticResource ImageLogoConverter}}" />
How many instance does of ImageLogoConverter will be there?
Is it good idea to use converter in ViewModel, if not then what is the best way to access converted value of ViewModel property.
Is it good idea to use converter in ViewModel?
No. Why would you use a converter in a view model where you can return the converted value directly? Converters are used in the view, typically to convert a non-view friendly value that the view model returns.
If not then what is the best way to access converted value of ViewModel property?
You can simpy return an already converted value from the view model, i.e. instead of binding to a Uri property, you may bind directly to an ImageSource property.
This is the recommnded approach if you for example intend to display a lot of elements in a ItemsControl. Then you probably don't want to invoke a converter for each visible element for performance reasons.
I suppose you created the converter as a resource like this:
The number of instances now depends on the scope where the converter resource is declared. If you create it in <Page.Resources>, one instance will be created to be used by the page. If you create it in App.xaml in <Application.Resources> it will be an application-wide instance. Of course, you can even use a narrower scope - create it as a resource of a single control in your XAML tree for example - in any case, a single instance is created when instance of the parent is created.
The situation gets a bit more interesting if you embed it in a ItemTemplate of a list control. Thanks to virtualization, the system will not actually create one instance for each item. Instead, it will create only so many instances as fit on the screen and they get reused when the user scrolls.
Some MVVM developers don't like value converters, but others use them extensively. It really is a matter of preference. In cas you expect the underlying data to change often, it is advisable to keep the code in the converter as performant as possible as it runs on the UI thread.

MVVM practices: expose viewmodel class inside a control

I've edited the question to make what I want to obtain clearer.
Here's the original question:
I'm working on a class that inherits from Control which will be used in my View and includes some Dependency Properties.
One of these DPs is an IEnumerable(Of RfidTag) and will be bound to an ObservableCollection(Of RfidTag) inside the VM.
The class RfidTag is defined as public class in the same file where the VM's class resides.
The questions are:
1. is it a good practice to expose a VM-related class to a Control class?
2. is the VM source file a good place for the RfidTag class?
UPDATE 1
In my application logic (I think I could say in my Model) there is an event published throught an Eventaggregator. The event's payload is a List of ModelRfidTag (that is the model class).
My VM subscribes to this event and I made the RfidTag class to wrap my Model class and provides some additional properties related only to the VM.
When the event handler inside the VM is executed, it makes an ObservableCollection(Of RfidTag) bindable from the view.
Then in the View I've a bounch of my control instances like that
<c:RfidTagPresenter
TagPosition="1"
Collection="{Binding RfidTagList, Mode=OneWay}" />
Then in my RfidTagPresenter (the class that inherits from Control) I've a DP of type RfidTag (called RfidTagResult) that returns the object in the OC which has the Position property (property available inside the RfidTag class) equal to the value set by the TagPosition DP.
In this way, the ControlTemplate of the RfidTagPresenter can bind its elements to the desired object.
This is the simplification of what I want to make. In the actual application there are some other DPs on which the RfidTagResult selection is performed
UPDATE 2
After a bit of research, seem that I can solve one problem with an indexed property that return (in the get method) the object from the collection I want to bind.
However a problem still exist: My control need to have a DP of type of RfidTag so that the relative ControlTemplate can bind to the property declared in the RfidTag class.
So: Is it possible (read: a good practice) to have a DP of a type that is a VM related class?
In other words: Can a custom control know about the class type used by the VM?
I will try to go all over your question (if I miss something let me know) but first you should explain the purpose of binding a Collection in a control as a DP.
is it a good practice to expose a VM-related class to a Control class?
RfidTag, I suppose, is a Model. What you are really doing here is binding a Model in your control which go against the MVVM pattern. You should think about the next question... Do you really need all your RfidTag to be shown in the View ? If you need to show a name, an ID... you could just create an IEnumerable<string> as DP (which is correct) and then in your VM instead of an ObservableCollection<RfidTag> you would have an ObservableCollection<string>.
Some simple theory. In MVVM, VM adapts the Model to the View. So your VM should have everything that will be shown in your View.
is the VM source file a good place for the RfidTag class?
RfidTag is a Model so there's no better place for it :)

In automic how to communicate between the job in workflow?

As we know that one job can call in multiple workflow.
I need an variable which give me the workflow name at time of runtime so that I can write this information in log.
It should not be global variable. it must be define with in the scope of workflow.
In the process tab - where I assume your code is and where you need the parent object (workflow in your case) - you can click on the "Variables..." menu item.
In the popped up variable picker you need to change to "Object" for "Category" and pick "Processor (name)".
This will provide the name of the superordinate (fancy word for parent) object - in your case the Workflow. Also available would be "Processor (RunID)" providing the ID.
This will insert the "system-variable" &$PROCESSOR#, which holds the name of the parent object or you simple copy that variable from my answer :)

A question about the Repository pattern and MVVM

I have a repository named MemberRepository which is used by the MemberListViewModel and the MemberEditViewModel. In the repository I have my GetMember(), CreateMember, SaveMember, Rollback(), and DeleteMember().
Throughout my app I have numerous lookup tables that populate comboboxes. Example Status, Trade Code, Agent, User etc. Where do I place the GetUsers, GetStatuses(), GetTradeCodes() methods? In the appropriate repositories in which they are used?
For example, the member view model needs a list of statuses, trade codes, classes, etc. So I would put the gets for these in the MemberRepository?
Bill
Ok, so your MemberListViewModel is for a listing page and your MemberEditViewModel is an editing page.
What I would do, in my model, is expose the following classes:
ListMembersTask
EditMemberTask
You inject these with all the repositories each one would need, and they expose the properties and methods needed by some abstract thing that's performing each task. For instance, ListMembersTask might have a method called CreateMember() that returns a new EditMemberTask initialized with an empty Member object.
Your ViewModel then gets injected with the appropriate Task (so MemberListViewModel gets injected with ListMembersTask, etc.). Your MemberListViewModel would have a RelayCommand that called CreateMember() and took the returned EditMemberTask, injected it into a MemberEditViewModel and passed the new MemberEditViewModel to the presenter.
If you follow that approach, then the Repositories are only responsible for persistence. A task wraps up the state of the business logic during a session, and a view-model just makes a task bindable.
The next step I've been working on is to dispense with the Task-specific view-models, and I now hand a raw Task to the Presenter, and it inspects the object and builds a view-model hierarchy for the task out of elementary view-model elements (like EditTextViewModel, ChooseOneViewModel, DockingLayoutViewModel, etc.).

Loading workflow activity dynamically from XOML

I am trying to implement an activity similar to InvokeWorkflow, which could dynamically load a XOML file, instantiate an activity tree from it, and use it as its only child.
This would be similar to InvokeWorkflow except that the activities which are dynamically loaded are inlined into the main workflow (which is better from a monitoring perspective).
I looked at XamlReader as a potential way of doing this, but apparently it is not suitable for loading workflows (only UI stuff).
Thanks,
Julien
Achieving your goal here is likely to be quite tricky however lets start with the easy bit:-
You can reconstruct a workflow from XOML using the WorkflowMarkupSerializer found in the System.Workflow.ComponentModel.Serialization namespace.
var serializer = new WorkflowMarkupSerializer();
object root = serializer.Deserialize(myXmlReader);
Similarly you could reconstruct a "snippet" of activities held in something that inherits from CompositeActivity using the CompostiteActivityMarkupSerializer.
However, to integrate the new root activity into the currently running workflow requires more work. You need to use an instance of the WorkflowChanges class to make the new activity by modifing the Workflow definition used by the current instance.
Now the documentation is some what sketchy and even a little evasive on this subject. Two important points can be gleaned though:-
Ultimately a call to ApplyWorkflowChanges is needed and this member has protected accessibility.
The documentation indicates that this needs to occur on the root activity of a workflow.
Hence we can deduce that we will need a custom root activity to at least assist in this requirement.
There are probably more ways that this could be structured but lets assume we have a SequenceActivity in which we have a custom "InvokeWorkflow" activity performing the workflow modification and we intend to place the resulting new activity at the end this containing sequence.
First we'll need an interface definition which we can implement on the custom root activity:-
internal interface IModifiableWorkflow
{
void ApplyWorkflowChanges(WorkflowChanges workflowChanges);
}
In our custom root activity we would implement this interface explicitly:-
public class CustomSequentialActivity : SequentialWorkflowActivity, IModifiableWorkflow
{
void IModifiableWorkflow.ApplyWorkflowChanges(WorkflowChanges workflowChanges)
{
base.ApplyWorkflowChanges(workflowChanges);
}
}
In the Execute method of the custom "InvokeWorkflow" activity:-
// Get root activity
var root = this.Parent;
while (root.Parent != null) { root = root.Parent; }
// Create an instance of WorkflowChanges based on the root activity
var changes = new WorkflowChanges(root);
//Find the parent sequence activity in the transient workflow definition
var target = changes.TransientWorkflow.GetActivityByName(this.Parent.Name);
Activity newActivity = YourCodeToLoadActivityDetailsFromXoml();
target.Activities.Add(newActivity);
//Apply the new changes
((IModifiableWorkflow)root).ApplyWorkflowChanges(changes);
Note I haven't actually tested any of this, its cobbled together from crumbs of info buried in the documentation.
Thanks so much Anthony.
I have to say that your dynamic workflow modification is cool, but it was a little scary. I ended up composing workflows using a modification of Jon Flander's CallWorkflowActivity.
Some tricks I learned with XOML-only workflows loaded at runtime (using WF 3.5):
remove x:Class attribute inside the XOML
delete the code-behind file
for the VS designer to work, those XOML files need to be separated in their own projects (no code, such as base activities or common types, in the project where the XOML is located)
mark the XOML as Content in VS and Copy Always so it is placed with your binaries
even so, VS 2008 usually needs a full Rebuild in order to properly copy newly modified XOML files...
you may need to set breakpoints manually, as explained here