Click here to Skip to main content
15,895,740 members
Articles / Desktop Programming / XAML

A dynamic Rehosted Workflow Designer for WF 4

Rate me:
Please Sign up or sign in to vote.
4.85/5 (26 votes)
29 Jul 2012CPOL10 min read 112.1K   11.8K   78  
This article presents a framework allowing you to integrate the workflow designer more easily in your own applications
using System;
using System.Activities.Presentation.Services;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using RehostedDesigner.Designer.ViewModels.Contracts;
using Selen.WorkflowDesigner.Contracts;
using Selen.WorkflowDesigner.Storage.Contracts;

namespace Selen.WorkflowSaveModule.ViewModels
{
    public class WorkflowSaveViewModel
    {
        private readonly Dispatcher _dispatcher = Dispatcher.CurrentDispatcher;
        private readonly IDesignerViewModel _designerViewModel;
        private readonly WorkflowStorageData _storageData;
        private readonly IMainViewModel _mainViewModel;

        public WorkflowSaveViewModel(
            IDesignerViewModel designerViewModel,
            IMainViewModel mainViewModel,
            WorkflowStorageData storageData)
        {
            this._storageData = storageData;
            this._mainViewModel = mainViewModel;
            this._designerViewModel = designerViewModel;
        }

        #region Commands

        private RelayCommand _saveCommand;
        public RelayCommand SaveCommand
        {
            get
            {
                this._saveCommand = this._saveCommand ?? new RelayCommand(obj => new Task(this.Save).Start(), 
                    obj => this._storageData.DesignerModel != null && 
                        this._designerViewModel.CurrentSurface != null && 
                        this._designerViewModel.CurrentSurface is IDesignerSurface);

                return this._saveCommand;
            }
        }
        private void Save()
        {
            this._mainViewModel.PostStatus("Saving workflow ...");

            var surface = (IDesignerSurface)this._designerViewModel.CurrentSurface;
            this._storageData.DesignerModel.RootActivity = surface.Designer.Context.Services.GetService<ModelService>().Root.GetCurrentValue();

            if (!this.ValidateDesigner(surface)) return;
            if (!this.ValidateOverride()) return;

            try
            {
                if (this._storageData.WorkflowType == null) throw new InvalidOperationException("no workflow type");

                if (this._storageData.WorkflowType.StorageAdapter.SaveDesignerModel(this._storageData.DesignerModel))
                {
                    this._storageData.DesignerModel.ApplyKey();
                    this._mainViewModel.PostStatus("Workflow saved");
                }
                else
                {
                    this._mainViewModel.PostStatus("Save canceled");
                }
            }
            catch (ApplicationException apEx)
            {
                this._mainViewModel.On_DisplayErrors(new[] { new DesignerErrorDefinition { ErrorMessage = apEx.Message } });
                this._mainViewModel.PostStatus("Save error");
            }
            catch (Exception ex)
            {
                this._mainViewModel.PostStatus("Save error: Internal error");
                Trace.TraceError(ex.Message);
            }
            finally
            {
                this._dispatcher.BeginInvoke(CommandManager.InvalidateRequerySuggested);
            }
        }
        #endregion

        #region PrivateHelpers

        private bool ValidateOverride()
        {
            if (this._storageData.DesignerModel != null && this._storageData.DesignerModel.HasKeyChanged)
            {
                var entity = this._storageData.WorkflowType.StorageAdapter.GetDesignerModel(this._storageData.DesignerModel.Key);

                if (entity != null)
                {
                    var result = MessageBoxResult.No;
                    this._dispatcher.Invoke(() => result = MessageBox.Show("An existing workflow will be overriden, do you want to continue?", "confirm save",
                        MessageBoxButton.YesNo, MessageBoxImage.Question));

                    if (result == MessageBoxResult.No)
                    {
                        this._dispatcher.BeginInvoke(CommandManager.InvalidateRequerySuggested);
                        this._mainViewModel.PostStatus("Save canceled");
                        return false;
                    }

                    this._storageData.WorkflowType.StorageAdapter.DeleteDesignerModel(entity.Key);
                }
            }

            return true;
        }
        private bool ValidateDesigner(IDesignerSurface surface)
        {
            var errors = surface.GetLastErrors();
            if (errors.Count == 0) return true;

            this._mainViewModel.On_DisplayErrors(errors.Select(el => new DesignerErrorDefinition { ErrorMessage = el.Message }));
            this._dispatcher.BeginInvoke(CommandManager.InvalidateRequerySuggested);
            this._mainViewModel.PostStatus("Save error");
            return false;
        }
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Student
Germany Germany
I´m a student and hobby programmer from Germany.

Comments and Discussions