AccessTodBase Windows Workflow

AccessTodBase Activity предназначена для экспорта данных из базы данных Access в Dbf файл. В чем смысл разработки этой программы? Ведь в Access существует стандартная процедура экспорта данных. Дело в том, что при экспорте данных в Access есть проблема, числа, большие 15 знаков не могут быть нормально экспортированы в dBase, они урезаются до 15 символов. AccessTodBase решает эту проблему.
Программа интресна тем, что состоит только из Activity. Например, стандартный OpenFileDialog выполнен в виде Activity. Процедура преобразования из Access в DBf - это тоже Activity.
Интересно, на мой взгляд, и то, что все Activity помещены в единый Workflow, при запуске которого указывается код подлежащий выполнению Activity. Например, запуск Workflow c кодом операции "1" вызовет выполнение Activity, обеспечивающей диалог для выбора базы данных Access, запуск Workflow c кодом "2" - диалог для выбора dBase, "3" - вызов Activity, которая экспортирует данные из Access в dBase.
Надо понимать, что вызов любого Workflow - это запуск дочернего потока выпонения, каким бы методом мы его не вызывали, и естествено (или не естественно :)), надо подумать о синхронизации потоков.
Представлен рабочий проект MS Visual Studio 2012 WorkFlow + Windows Forms Application. Кстати, Workflow запускается из обычного Windows Forms приложения.
1. OpenFileDialog Activity. Выбор базы данных Access.
Ниже приведен текст стандартного OpenFileDialog для Access, выполненого в виде Activity. Диалог для dBase аналогичен.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Windows.Forms;

namespace AccessTodBase
{
    public sealed class DialogAccess : CodeActivity
    {
        [RequiredArgument]
        [DefaultValue(null)]
        public InArgument<string>  Drive            { get; set; }
        public OutArgument<string> OutPathAccess    { get; set;}

        private OpenFileDialog dialog;

        protected override void Execute(CodeActivityContext context)
        {
            // Open Dialog
            dialog = new OpenFileDialog();
            dialog.InitialDirectory = context.GetValue(Drive);
            dialog.Filter = "txt files (*.accdb)|*.accdb|All files (*.accdb)|*.accdb";
            dialog.FilterIndex = 2;
            dialog.RestoreDirectory = true;
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                OutPathAccess.Set(context, dialog.FileName);
            }
        }
    }
}
2. Перенос данных из Access в dBase.
Ниже показана Activity выполняющая перенос данных из одной базы данных в другую.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.IO;

namespace AccessTodBase
{
    public sealed class ActivityTransfer : CodeActivity
    {
        // Define an activity arguments of type string
        [RequiredArgument]
        [DefaultValue(null)]
        public InArgument<string>   PathAccess      { get; set; }
        public InArgument<string>   PathdBase       { get; set; }
        public OutArgument<string>  ResultTransfer  { get; set; }
        
        // Define private temporary
        private OleDbConnection     connectAccess, connectDbf   = null;
        private OleDbCommand        commandAccess, commandDbf   = null;
        private OleDbDataAdapter    adapterAccess, adapterDbf   = null;
        private OleDbDataReader     reader                      = null;
        private DataTable           dataTableAccess             = null;
        private DataTable           dataTableDbf                = null;
        private DataRow             rowDbf                      = null;
        private string              stringCommandAccessSQL      = null;
        private string              stringCommanddBaseSQL       = null;
        private string              readdBase                   = null;

        protected override void Execute(CodeActivityContext context)
        {
            string connectStringAccess  =   context.GetValue(PathAccess);
            string connectStringdBase   =   context.GetValue(PathdBase);
            try
            {
                if (String.IsNullOrEmpty(connectStringAccess))  throw new ArgumentNullException("Value", "File Name Access is null");
                if (String.IsNullOrEmpty(connectStringdBase))   throw new ArgumentNullException("Value", "File Name dBase is null");
                // Read data Access table
                stringCommandAccessSQL = @"SELECT OutputTable.* FROM OutputTable";
                connectAccess = new OleDbConnection(connectStringAccess);
                connectAccess.Open();
                commandAccess = new OleDbCommand(stringCommandAccessSQL, connectAccess);
                adapterAccess = new OleDbDataAdapter(commandAccess);
                reader = commandAccess.ExecuteReader();
                dataTableAccess = new DataTable();
                dataTableAccess.Load(reader);
                connectAccess.Close();

                // Connect dBase
                stringCommanddBaseSQL   = @"INSERT INTO INPUTP (NUM, FAM, IM, OT) VALUES (?, ?, ?, ?)";
                readdBase               = @"SELECT INPUTP.* FROM INPUTP";
                connectDbf = new OleDbConnection(connectStringdBase);
                connectDbf.Open();

                commandDbf = new OleDbCommand(readdBase, connectDbf);
                adapterDbf = new OleDbDataAdapter(commandDbf);

                adapterDbf.InsertCommand = new OleDbCommand(stringCommanddBaseSQL, connectDbf);
                adapterDbf.InsertCommand.Parameters.Add("@NUM", OleDbType.Numeric, 10, "NUM");
                adapterDbf.InsertCommand.Parameters.Add("@FAM", OleDbType.Char, 40, "FAM");
                adapterDbf.InsertCommand.Parameters.Add("@IM",  OleDbType.Char, 40, "IM");
                adapterDbf.InsertCommand.Parameters.Add("@OT",  OleDbType.Char, 40, "OT");

                dataTableDbf = new DataTable();
                adapterDbf.Fill(dataTableDbf);

                int i = 0;
                foreach (DataRow row in dataTableAccess.Rows)
                {
                    ++i;
                    rowDbf = dataTableDbf.NewRow();
                    rowDbf["NUM"]   = row[0];
                    rowDbf["FAM"]   = row[1];
                    rowDbf["IM"]    = row[2];
                    rowDbf["OT"]    = row[3];
                    dataTableDbf.Rows.Add(rowDbf);

                    /* Debug                   
                    if (i == 100)
                    {
                        adapterDbf.Update(dataTableDbf);
                        connectDbf.Close();
                        Console.WriteLine("O.K.");
                        break;
                    }
                    */
                }
                adapterDbf.Update(dataTableDbf);
                connectDbf.Close();
                ResultTransfer.Set(context, "O.K.");
            }
            catch (Exception ex)
            {
                ResultTransfer.Set(context, ex.ToString());
            }
        }
    }
}
3. Полный текст программы, выпоняющей запуск Workflow и конкретных Activity.
Оператор должен выбрать пути нахождения баз данных и далее запустить процесс. Повторюсь, запуск Workflow выполняется из Windows Forms Application.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Activities;
using System.Threading;
using System.Timers;
using AccessTodBase;

namespace AccessTodBase
{
    public partial class SetParametersForm : Form
    {
        WorkflowApplication wfApp       = null;
        AutoResetEvent waitHandler      = null;
        WorkFlowTransfer addwf          = null;
        WorkflowInvoker  invoker        = null;

        private string connectStrAccess = string.Empty;
        private string connectStrDbf    = string.Empty;
        private int codeActivity        = 0;
        public int endWorkFlow          = 0;
     
        public SetParametersForm()
        {
            InitializeComponent();
            waitHandler = new AutoResetEvent(false);
        }

        // Start transfer data
        private void Start_Click(object sender, EventArgs e)
        {            
            try
            {
                // Set show gif file
                pictureBoxWait.Visible  = true;
                endWorkFlow             = 0;

                // Define local temporary
                string result           = string.Empty;
                string fileDirectory    = String.Empty;
                
                // Set code operation for ActivityTransfer
                codeActivity = 3;

                // Set Connect string for Access
                connectStrAccess    = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + textBoxAccess.Text;
                
                // Set connect string for Dbf
                int index           = textBoxdBase.Text.LastIndexOf(@"\");
                fileDirectory       = textBoxdBase.Text.Substring(0, index + 1);
                connectStrDbf       = @"Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" + fileDirectory + @"; Extended Properties=dBASE IV";

                // Set AutoResetEvent
                waitHandler = new AutoResetEvent(false);

                // Create WorkFlowTransfer
                WorkFlowTransfer addwf  = new WorkFlowTransfer()
                {
                    PathAccessArgument  = new InArgument<String>(connectStrAccess),
                    PathdBaseArgument   = new InArgument<String>(connectStrDbf),
                    CodActivityArgument = new InArgument<int>(codeActivity)
                };

                // Create WorkflowApplication
                wfApp = new WorkflowApplication(addwf);
              
                // Create event handler wfApp.Completed
                wfApp.Completed = (workflowApplicationCompletedEventArgs) =>
                {
                    result = workflowApplicationCompletedEventArgs.Outputs["ResultWorkFlow"].ToString();
                    if (result != "O.K.") MessageBox.Show("Errot transfer Activity ...");
                    waitHandler.Set();
                    endWorkFlow = 1;
                };

                // Start workflow
                myTimer.Enabled = true;
                wfApp.Run();
            }
            catch (Exception ex)              
            {
                MessageBox.Show(ex.ToString());
            }           
        }

        // Select Path Access DataBase
        private void PathAccess_Click(object sender, EventArgs e)
        {
            try
            {
                // Set code Activity
                codeActivity = 1;
                addwf = new WorkFlowTransfer() { CodActivityArgument = new InArgument<int>(codeActivity) };
                invoker = new WorkflowInvoker(addwf);
                invoker.InvokeCompleted += delegate(object obj, InvokeCompletedEventArgs args)
                {
                    textBoxAccess.Text = args.Outputs["ResultWorkFlow"].ToString();
                    waitHandler.Set();
                };
                invoker.InvokeAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error select Access", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        // Select path dBase DataBase
        private void PathdBase_Click(object sender, EventArgs e)
        {
            try
            {
                // Set code Activity
                codeActivity = 2;
                addwf = new WorkFlowTransfer() { CodActivityArgument = new InArgument<int>(codeActivity) };
                invoker = new WorkflowInvoker(addwf);
                invoker.InvokeCompleted += delegate(object obj, InvokeCompletedEventArgs args)
                {
                    textBoxdBase.Text = args.Outputs["ResultWorkFlow"].ToString();
                    waitHandler.Set();
                };
                invoker.InvokeAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error select dBase", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        // Tick metod timer
        private void myTimer_Tick(object sender, EventArgs e)
        {
            if (endWorkFlow == 1)
            {
                pictureBoxWait.Visible = false;
                myTimer.Enabled = false;
            }
        }
     
    }
}

Visual Studio 2012 проект можно загрузить.
Евгений Вересов.
08.04.2013 года.