locked
INotifyPropertyChanged interface for variable. WPF - WF binding in c# RRS feed

  • Question

  • I need event from changed variable, something like  INotifyPropertyChanged. I know that in XAML I can make binding between FrameworkElement and variable. How I can make this in C#?
    Thursday, August 13, 2009 3:09 PM

Answers

  • Now, I didn't say you can't use them together, just that it takes more work to get them integrated than simply binding and you have to understand the context that each is working in.  One way you can use binding is to create an object (say a customer class) and use that in your WPF UI - use binding, INotifyPropertyChanged, and all that good stuff.   Then, pass that object as an argument to your workflow and operate on the object.  If you modify the object in the workflow, your UI can update as the object updates. 

    This gets a little trickier if you need persistence and long running workflows, but could still be accomlished by passing in the object with custom activities that use bookmarks. 

    So, while binding directly to a variable from outside the workflow might not work, you now have two options that do - the one shown in the example where the WPF XAML is part of the workflow, and one where you don't bind to variables, rather you bind to an object and pass it as an argument to the workflow. 

    HTH,
    Matt

    Check out Pluralsight On Demand! http://www.pluralsight.com/main/olt/
    Thursday, August 20, 2009 3:20 PM

All replies

  • In order to better understand the question

    Are you talking about variables which you create in the Workflow Designer?

    Do you want to use the INotifyPropertyChanged interface directly, or do you just want to do a {Binding...} in WPF XAML? Can you be more specific about what you want to bind to?

    Tim
    Thursday, August 13, 2009 3:50 PM
  • I mean C#:
    public RecordEegWorkflow()
            {
           
                Variable<RecordingCommand> _recordingCommand = new Variable<RecordingCommand> { Name = "_recordingCommand" };
    
    ...
    
     //  recordingInitialisedState           
                FlowStep recordingInitialisedState = new FlowStep
                {
                    Action = new Pick
                    {
                        Branches =
                        {
                            new PickBranch
                            {
                                Trigger = new ReadBookmark<string> { InputCommand = RecordingCommand.Start, ResultCommand = _recordingCommand }
                            },
                            new PickBranch
                            {
                                Trigger = new ReadBookmark<string> { InputCommand = RecordingCommand.Stop, ResultCommand = _recordingCommand }
                            }
                        }
                    },
    
                };
    
    ...
    
    this.Body = () => new Flowchart
                {
    
                    DisplayName = "EEG Recording",
                    Variables = { _recordingCommand },
    
                    StartNode = openEegView,
                    Nodes = {
                        openEegView,
                        startOnLineView,
                        recordingInitialisedState,
                        recordingStartedState,
                        recordingPausedState,
                        approvalSwitch,
                        stopOnLineView,  
                        approvalSwitch2,
                    }
    
                };
    I have RecordEegWorkflow with  _recordingCommand variable. This variable will be changed in recordingInitialisedState step. I have WFP GUI.
    1) How I can binding my GUI wpf element with _recordingCommand variable? 2) How I can get notify event if  _recordingCommand will be changed?
    Thursday, August 13, 2009 4:12 PM
  • OK, I think I understand where you are coming from.

    I think the problem is you are trying to do something in a way that made sense in Workflow 3 but no longer makes sense to do the same way in the Workflow 4 world.

    In workflow 3 there were dependency properties on the activities, and these were used for data flow in the workflow, and you could bind directly to them using WPF.

    In Workflow 4 everything has been redesigned, from scratch. For data flow it is necessary to use Variables instead of the dependency properties when you want to pass data around in your workflow. So it is true that Workflow 4 Variables solve the 'data flow problem'. However, they do not solve the 'can be manipulated easily using WPF problem'.

    At this point I should explain what is the way using WPF to bind to variables, activities, and properties on them that is used in the new visual designer for Visual Studio 2010 - and in the rehostable WF designer? It is not by binding directly to the objects. There is a layer of abstraction in between, which implements INotifyPropertyChanged and wraps the workflow objects. A layer of abstraction called the ModelTree. This provides a nice WPF-friendly wrapper for pretty much any object you care to wrap.

    If you haven't had a look yet you might want to research more about rehosting the workflow designer and Model Tree - I would recommend Matt's blog for further reading:

    http://blogs.msdn.com/mwinkle/archive/2009/06/17/introduction-to-wf-designer-rehosting-part-1.aspx

    In theory you can use the ModelTree and provide your own UI on top of it. In practice I haven't seen anyone do it yet.

    Tim

    Thursday, August 13, 2009 4:27 PM
  • It sounds like what you want is your UI at runtime, not design time, to update with this change, correct?  One thing that is the same between WF3 and WF4 is that you don't have direct access to the workflow instance.  if you want to get notification of changed runtime values, in your hosting application, then you should look at creating a custom tracking participant and the associated tracking profile to get those notifications. 

    HTH,
    matt


    Check out Pluralsight On Demand! http://www.pluralsight.com/main/olt/
    Thursday, August 13, 2009 10:03 PM
  • Thank you for answer. Of course I mean runtime, not design time. There is one sample in SDK WPFWFIntegration. This sample use a binding between UI and workflow in XAML:
    <w:Sequence.Variables>
        <w:Variable Name="firstName" x:TypeArguments="c:String" Default="First" />
        <w:Variable Name="lastName" x:TypeArguments="c:String" Default="Last" />
      </w:Sequence.Variables>
      <w:Sequence.Activities>
        <s:ShowWindow>
          <Window xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
            x:Name='theWindow' Title='WPF and WF' Width='350' Height='200' >
            <Grid MinWidth='200'>
              <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
              </Grid.ColumnDefinitions>
              <Label>First Name</Label>
              <Label Grid.Row='1'>Last Name</Label>
              <TextBox Text='{Binding firstName, UpdateSourceTrigger=PropertyChanged}' Grid.Column='1' />
              <TextBox Text='{Binding lastName, UpdateSourceTrigger=PropertyChanged}' Grid.Row='1' Grid.Column='1' />
              <Button Content='Close' Grid.Row='3' Grid.ColumnSpan='2' >
                <Button.Click>
                  <s:DelegateActivity>
                      <s:CloseWindow Window='[theWindow]' />
                  </s:DelegateActivity>
                </Button.Click>
              </Button>
            </Grid>
          </Window>
        </s:ShowWindow>
    1. How I can make the same binding in C#???  2. Or more detail question: How I can bind UI with Collection of BookmarkInfo? I want to set buttons states depend from the available bookmarks in the current Pick activity of my Flowchart. Now I have this code:
    in WPF GUI:

    void UpdateButtons() 
            {
                _Start.IsEnabled = false;
                _Pause.IsEnabled = false;
    
                foreach (BookmarkInfo bookmark in _workflowInstance.GetAllBookmarks()) 
                {
                    switch (bookmark.BookmarkName)
                    {
                        case "Start":
                            _Start.IsEnabled = true;
                            break;
                        case "Pause":
                            _Pause.IsEnabled = true;
                            break;
                        case "Stop":
                            _Stop.IsEnabled = true;
                            break;
    
                    }
                }
            }
     in WF child activity:
    public class ReadBookmark<T> : NativeActivity<T>
        {
            public delegate void OnBookmarksChanged();
             
            public ReadBookmark(): base() { }
    
            public OutArgument<RecordingCommand> ResultCommand { get; set; }
    
            public RecordingCommand InputCommand { get; set; }
    
            protected override void Execute(ActivityExecutionContext context)
            {
                Bookmark bookmark= context.CreateNamedBookmark(this.InputCommand.ToString(), new BookmarkCallback(this.Continue));
                // TODO: STATIC METHOD has to be changed 
                RecordEegWorkflow.OnBookmarksChanged();
                
            }
    In parent workflow:
    internal static void OnBookmarksChanged()
            {
                Page.UpdatePage();
            }   

    This solution is possible. But I prefer binding instead of static methods :).

    Friday, August 14, 2009 7:45 AM
  • What about using the GetAllBookmarks method on the workflow instance class?  You could use an ObjectDataProvider and use code to set the objectinstance property to your workflow instance.  Then you can use that resource in a binding and get all the bookmarkinfo objects on the workflow. 

    Otherwise, using the sample you refer to, I think you are going to have a lot of work to get it all hooked together, especially if your WPF XAML and our WF XAML are going to be separate. 

    Matt

    Check out Pluralsight On Demand! http://www.pluralsight.com/main/olt/
    Friday, August 14, 2009 3:51 PM
  • Thank you,
    Of course I can bind WPF buttons with bookmarkinfo using  GetAllBookmarks and ObjectDataProvider. But what about variables? I don't have access to workflow variables from workflow instance object. How I can change variables from WPF GUI (like in SDK "WPFWFIntegration" xaml sample but in c#)? I want to use WF for program some business logic in WPF application. I need some general solutions for binding or dataexchange between WFP and WF.

    May be more detail question, how I can implement this use case:

    I have a workflow with some activity. The first activity has WPF text control. I want to save entered text value from control in workflow variable and use this variable in other activities.

    Alexey

     

    Wednesday, August 19, 2009 3:35 PM
  • Generally speaking, if you are outside the workflow, you don't have access to that data directly, as you have stated.  You can either send a message to the workflow to retrieve the data - using the WCF activities or custom activities - or you can resume the workflow and have it show the window in question much like the WPF/WF integration sample you mentioned.  Typically, if my application needs access to data both in the workflow and outside the workflow, I make sure to store that data in a database where both can retrieve it rather than locking that data up in the workflow.  Then your activities can either operate on that data as it gets passed from the host, or they can lookup the data from the database to get the most recent data to act upon. 

    Matt


    Check out Pluralsight On Demand! http://www.pluralsight.com/main/olt/
    Wednesday, August 19, 2009 3:48 PM
  • It is a pity! I can simple program my business logic with WF,  but I cannot simple integrate it with WPF GUI. I think it's a large overhead to use WCF  or database for binding WPF and Workflow. So, I cannot simple use WF in desktop application - it is a very pity! A specially, that WF 4.0 and WPF have the same dependency/binding namespaces.


    Alexey. 
    Thursday, August 20, 2009 7:46 AM
  • Now, I didn't say you can't use them together, just that it takes more work to get them integrated than simply binding and you have to understand the context that each is working in.  One way you can use binding is to create an object (say a customer class) and use that in your WPF UI - use binding, INotifyPropertyChanged, and all that good stuff.   Then, pass that object as an argument to your workflow and operate on the object.  If you modify the object in the workflow, your UI can update as the object updates. 

    This gets a little trickier if you need persistence and long running workflows, but could still be accomlished by passing in the object with custom activities that use bookmarks. 

    So, while binding directly to a variable from outside the workflow might not work, you now have two options that do - the one shown in the example where the WPF XAML is part of the workflow, and one where you don't bind to variables, rather you bind to an object and pass it as an argument to the workflow. 

    HTH,
    Matt

    Check out Pluralsight On Demand! http://www.pluralsight.com/main/olt/
    Thursday, August 20, 2009 3:20 PM