News


I'm not a desktop application developer. I wrote only one app using the WinForms, but I must tell, it was interesting experience. Now I'm writting second WinForms app and second time, I needed the possibility to updating the progress bar in an app.

So I think this is a good opportunity to put on the blog the code snippet for that to have a place where I can have some useful code for future references.

 

Ok, so let's go to the solution details. As every desktop application developer know (or should know), the WinForms controls can be accessed/property changed only from the same thread in which they were created. If we have an application and we try to change the progress bar value in some long-running algorithm and all works on the same thread, the program won't be responding to the moment that the algorithm will be over. This is not a situation we want. We want to have a responding gui for e.g. stopping the executing algorithm or simply we want to move the app window to other place on the screen. To have this possibility, the algorithm must be running in other thread and only the gui must be updating from the main thread.

In .NET Framework we have few choices to do that. We have BackgroundWorker class, Dispatcher or we can use Tasks from Task Parallel Library. In my first WinForms app I used the Tasks from TPL to do that so I will focus on this topic in this post.

In the code below is the example

       public static File[] Search(SearchCriteria criteria, INotifyProgress notify)
        {
            notifyHandler = notify;
            TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
            if (notify != null)
            {
                notify.MinValue = notify.CurrentValue = 0;
                notify.MaxValue = criteria.Locations.ToList().Count;
            }

            notify.MaxValue = 1000;
            for (int i = 1; i <= 1000; i++)
            {
                var task = Task.Factory.StartNew((variables) =>
                    {
                        //simulate some long running algorithm
                        Thread.Sleep(100);

                        return (int)variables; //return the iteration number
                    }, i);
                task.ContinueWith(x =>
                {
                    notify.CurrentValue = x.Result;
                }, scheduler);
            }

            return null;
        }

The for loop is important in this solution. As you can see, for each iteration there is creating a new Task which doing some long-running calculations. When algorithm is finished, the result is returned. Each Task has also a continuation, which is executed after the Task is finished. In this sample, in the continuation there is taken the Task result and this result is set to the progress bar Value property. As I told earlier, the controls can be changed only from the thread where they were created. This is why I used the TaskScheduler.FromCurrentSynchronizationContext() method and set is as a second parameter to the Task continuation. You probably see that, the main Task has a second parameter too. In this parameter we can provide any outer variables which we want to have access to inside the Task. The variables is an alias for our outer variables.

 

The INotifyProgress interface need one line of explanation too. This is a contract for the class which is a simple wrapper for the WinForms progress bar control. I used it, because I don't want to have reference from the business logic to the gui controls.

    public interface INotifyProgress
    {
        int MaxValue { set; get; }
        int MinValue { set; get; }
        int CurrentValue { set; get; }
    }

    public class NotifyProgressBar : INotifyProgress
    {
        private ProgressBar progressBar;

        public NotifyProgressBar(ProgressBar progressBar)
        {
            this.progressBar = progressBar;
        }

        public int MaxValue
        {
            get
            {
                return progressBar.Maximum;
            }
            set
            {
                progressBar.Maximum = value;
            }
        }

        public int MinValue
        {
            get
            {
                return progressBar.Minimum;
            }
            set
            {
                progressBar.Minimum = value;
            }
        }

        public int CurrentValue
        {
            get
            {
                return progressBar.Value;
            }
            set
            {
                progressBar.Value = value;
            }
        }
    }


In my previous posts I have shown how to get xml data from database and deserialize it. But sometimes we want to work with the xml and do some operations on it. To working with xml, in the .net framework there are two tools for it. One is to use the XmlDocument class and second is the linq to xml with the XDocument class. I personally prefer to work with linq to xml, so I must convert the XmlDocument object to XDocument which I have after I took the xml from database.

 

To convert the XmlDocument to XDocument I have following extension methods

public static class XmlDocumentExtensions
{
    public static XDocument ToXDocument(this XmlDocument document)
    {
        return document.ToXDocument(LoadOptions.None);
    }

    public static XDocument ToXDocument(this XmlDocument document, LoadOptions options)
    {
        using (XmlNodeReader reader = new XmlNodeReader(document))
        {
            return XDocument.Load(reader, options);
        }
    }
}

 

To convert back, that means from XDocument to XmlDocument I have following extension method

        public static XmlDocument ToXmlDocument(this XDocument xDocument)
        {
            var xmlDocument = new XmlDocument();
            using(var xmlReader = xDocument.CreateReader())
            {
                xmlDocument.Load(xmlReader);
            }
            return xmlDocument;
        }


In one of my previous posts I have used my custom code to serialize and deserialized data to/from XmlDocument class.

Examples of use:

XmlDocument extensions=//some xml document taken from db
List<FileExtension> result = 
   SerializationUtils.DeSerializeXmlToObject<List<FileExtension>>(extensions);

List<FileExtension> extensions=//some new objects to save to database
XmlDocument serializedExtensions =
                SerializationUtils.SerializeObjectToXml<List<FileExtension>>(extensions);

The full code for this snippets:

    public static class SerializationUtils
    {
        public static T DeSerializeXmlToObject<T>(XmlDocument xmlDoc)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringReader reader = new StringReader(xmlDoc.InnerXml);
            T result = (T)serializer.Deserialize(reader);

            return result;
        }

        public static XmlDocument SerializeObjectToXml<T>(T obj)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            StringWriter w = new StringWriter();
            serializer.Serialize(w, obj);
            XmlDocument result = new XmlDocument();
            string xmlContent = w.ToString();
            result.LoadXml(xmlContent);
            return result;
        }
    }


In my previous post I have used a OperationsInTransaction.Execute() method. This is my simple wrapper for the NHibernate ISession and ITransaction method.

Normally when we want to execute some query in the transaction we must write this piece of code

using (ISession session = SessionFactory.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    try
                    {
                        //some query 
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                    }
                }
            }

Unfortunatelly we must write it every time when we want to execute some query on the database. Following the DRY principle I have created mini wrapper for it:

 public static class OperationsInTransaction
    {
        private static ISessionFactory sessionFactory;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (sessionFactory == null)
                {
                    sessionFactory = new NhibernateConfig().CreateFactory();
                }

                return sessionFactory;
            }
        }

        public static void Execute(IsolationLevel level, Action<ISession> operations)
        {
            using (ISession session = SessionFactory.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction(level))
                {
                    try
                    {
                        operations(session);
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }
            }
        }

        public static void Execute(Action<ISession> operations)
        {
            Execute(IsolationLevel.ReadCommitted, operations);
        }
    }

In this piece of code I'm creating every time in the background the new ISession and ITransaction objects when I'm execute some queries.

With this wrapper, what I need to write is only:

            OperationsInTransaction.Execute(session =>
            {
                var element = new SetAvailableExtensionsList().Execute(session, serializedExtensions);
                session.Save(element);
            });


I have a simple database table with only id and one xml column as shown below.

 extensions db table

 

 

 

 

 

In this column I have a list of available extensions saved as xml.

    public class FileExtensionsList
    {
        public FileExtensionsList()
        {
            Id = Guid.NewGuid();
        }

        public virtual Guid Id { set; get; }
        public virtual XmlDocument Extensions { set; get; }
    }

This xml I'm not creating manually. I have a custom entity which I serialize to xml:

 

    [XmlRoot("FileExtensionsList")]
    [Serializable]
    public class FileExtension
    {
        [XmlAttribute]
        public string Extension { set; get; }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if ((obj as FileExtension) == null)
                return false;

            if (this.Extension == ((FileExtension)obj).Extension)
            {
                return true;
            }

            return false;
        }

        public override int GetHashCode()
        {
            return Extension.GetHashCode();
        }
    }

And now I want to get this list from db using NHibernate. I'm not sure, in NHibernate 3.2 maybe there is already a build-in solution for working with xml columns, but in this post I will show how we can use a custom user type. This solution work for me from month and I don't see a reason why not to use it.

At the beginning we must add this custom user type. I have found somewhere a working implementation. Unfortunatelly I don't remember where. Code is below:

 /*
* UserType allowing easy saving of NHIbernate XmlDocument property.
*
* Example
* =======
*
* //Message.cs - Example class with a XmlDocument
* public class Message
* {
* public XmlDocument Body{get;set;}
* }
*
* //Message.hbm.xml - The mapping
*  *  *  *  * 
*
* History
* =======
* - This code was found online somewhere, sorry, I can't remember where :-(
* - I've tweaked it a little to work with 2nd level cache and NHibernate 2.1.x.
* - Tobin Harris
*/
    public class XmlType : IUserType
    {
        public new bool Equals(object x, object y)
        {
            if (x == null || y == null)
                return false;

            var xdoc_x = (XmlDocument)x;
            var xdoc_y = (XmlDocument)y;
            return xdoc_y.OuterXml == xdoc_x.OuterXml;
        }

        public int GetHashCode(object x)
        {
            return x.GetHashCode();
        }


        public object NullSafeGet(IDataReader rs, string[] names, object owner)
        {
            if (names.Length != 1)
                throw new InvalidOperationException("names array has more than one element. can't handle this!");

            var document = new XmlDocument();

            var val = rs[names[0]] as string;

            if (val != null)
            {
                document.LoadXml(val);
                return document;
            }

            return null;
        }

        public void NullSafeSet(IDbCommand cmd, object value, int index)
        {
            var parameter = (DbParameter)cmd.Parameters[index];

            if (value == null)
            {
                parameter.Value = DBNull.Value;
                return;
            }

            parameter.Value = ((XmlDocument)value).OuterXml;
        }

        public object DeepCopy(object value)
        {
            var toCopy = value as XmlDocument;

            if (toCopy == null)
                return null;

            var copy = new XmlDocument();
            copy.LoadXml(toCopy.OuterXml);
            return copy;
        }

        public object Replace(object original, object target, object owner)
        {
            throw new NotImplementedException();
        }

        public object Assemble(object cached, object owner)
        {
            var str = cached as string;
            if (str != null)
            {
                var doc = new XmlDocument();
                doc.LoadXml(str);
                return doc;
            }
            else
            {
                return null;
            }

        }

        public object Disassemble(object value)
        {
            var val = value as XmlDocument;
            if (val != null)
            {
                return val.OuterXml;
            }
            else
            {
                return null;
            }
        }

        public Types.SqlType[] SqlTypes
        {
            get
            {
                return new Types.SqlType[] { new SqlXmlType() };
            }
        }

        public Type ReturnedType
        {
            get { return typeof(XmlDocument); }
        }

        public bool IsMutable
        {
            get { return true; }
        }
    }

    public class SqlXmlType : Types.SqlType
    {
        public SqlXmlType()
            : base(DbType.Xml)
        {
        }
    }

    public class SqlXmlStringType : Types.SqlType
    {
        public SqlXmlStringType()
            : base(DbType.String, 4000)
        {
        }
    }

How this code works is not important. Important is that, now we can map our entities using this code and get access to the xml columns in our tables.

 

So let's map the entity from the beginning of this post.

    public class FileExtensionsListMap : ClassMapping<FileExtensionsList>
    {
        public FileExtensionsListMap()
        {
            Table("Extensions");
            Id(x=>x.Id, x=>x.Generator(Generators.Guid));
            Property(x => x.Extensions, x => x.Type<XmlType>());
        }
    }

I have used here the new to NHibernate 3.2 mapping by code, which I personally prefer much more than creating the *.hbm.xml files manually or even using the Fluent NHibernate. I used to have some problems with FN, maybe that is the reason..

Ok. When the mapping is created, we can configure the NHibernate and do some queries to check if everything works as we expecting. I'm not going to show right now hot to configure the NHibernate, this will be in one of my futures posts.

So let's look at the queries. To get the extensions as XMLDocument object we can use

    public class GetAvailableExtensionsList
    {
        public XmlDocument Execute(ISession session)
        {
            ICriteria criteria = session.CreateCriteria<FileExtensionsList>()
                  .SetProjection(Projections.Property("Extensions"));

            XmlDocument result = criteria.UniqueResult<XmlDocument>();
            return result;
        }
    }

If we want to work on the objects, not the xml itself we can deserialized it:

SerializationUtils.DeSerializeXmlToObject<List<FileExtension>>(extensions)

where extensions is the XmlDocument object.

With the raw xml we can use e.g. XSL Transforations to convert it to html and show on the page.

To set the data to database, the query looks that

    public class SetAvailableExtensionsList
    {
        public FileExtensionsList Execute(ISession session, XmlDocument extensions)
        {
            var element =
                session.CreateCriteria<FileExtensionsList>()
                .UniqueResult<FileExtensionsList>();

            if (element == null)
            {
                element = new FileExtensionsList();
            }

            element.Extensions = extensions;
            return element;
        }
    }

Now we must serialize the extensions and execute the ISession.Save() or ISession.Update() method on this query. ISession has the SaveOrUpdate() method too, but it need do something more to use it, because otherwise we will get an exception. In ony of my futures posts I will try to take a look at it.

In this example I'm using the ISession.Save() method

            XmlDocument serializedExtensions =
                SerializationUtils.SerializeObjectToXml<List<FileExtension>>(extensions);

            OperationsInTransaction.Execute(x =>
            {
                var element = new SetAvailableExtensionsList().Execute(x, serializedExtensions);
                x.Save(element);
            });

What is the OperationsInTransaction and how the serialize/deserialize mechanism is implemented  I will cover in other posts.

 

SQL Server has the possibility to e.g. query the xml in database with XPath, but I don't know yet if it is possible to do it with NHibernate. At this time I'm working with the xml after I took the entire file from the database in the c# code.

 

PS. This solution works properly with the xml column type in the database. But this is also possible to change the xml column type to nvarchar(max) and the solution will work in this situation too. To do it, we must change the code from

       public Types.SqlType[] SqlTypes
        {
            get
            {
                return new Types.SqlType[] { new SqlXmlType() };
            }
        }

to

        public Types.SqlType[] SqlTypes
        {
            get
            {
                return new Types.SqlType[] { new SqlXmlStringType() };
            }
        }