Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Wednesday, 29 August 2007

Dataset serialization shuffles tables

Yes, another serialization problem.

We have defined a BIG dataset, then we create a instance of it. In a certain portion of the code, we serialize it with a binary formatter, but ... surprise when we deserialize, the tables order doesn't match!

Well, so far I haven't had much time to investigate, but setting the remoting format to binary does the trick:

ProcessDataSet.RemotingFormat = SerializationFormat.Binary

Tuesday, 28 August 2007

Serialization of a class that inherit from HashTable (or any class that implements ISerializable)

This is another funny problem related to serialization. Have you serialized a class and when deserialized again all the field values are set to default values? Well, check if this is your case:

If you have a class (Class1) that inherits from another one that is ISerializable (i.e. HashTable),

then you MUST write a constructor to handle SerializationInfo:

[Serializable]
class Class1: Hashtable
{
    public Class1(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {

    }

    public Class1()
    {
    }
    protected int number;
    private int othernumber;
    public string text;

    public int OtherNumber
    {
        get
        {
            return othernumber;
        }
        set
        {
            othernumber = value;
        }
    }

    public int Number
    {
        get
        {
            return number;
        }
        set
        {
            number = value;
        }
    }
}

What’s the problem related to this?. Well, write a short win application with a button to test:

private void button1_Click(object sender, EventArgs e)
{

    Class1 obj = new Class1();
    obj.Number = 99;
    obj.OtherNumber = 100;
    obj.text = "hello";

    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    byte[] serializedObject;
    System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();

    //formatter.FilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.
    formatter.Serialize(memoryStream, obj);
    serializedObject = memoryStream.GetBuffer();

    System.IO.MemoryStream memoryStream2 = new System.IO.MemoryStream(serializedObject);
    Class1 obj2 = (Class1)formatter.Deserialize(memoryStream2);
}

And now, check the obj2: None of the values where properly retrieved! Why?

Well, as the Class1 class inherits from hashtable and hastable implements ISerializable, you need to write the special constructor above, but once you write the constructor, you are telling .net that you will be in charge of saving the data you really want to save… If you save no information for your fields, no data is saved when serialized, so no data is retrieved when deserialized.

The quick (and dirty ;) ) way to solve this: Use reflection to automatically traverse the properties and save them instead of write code to save them one by one:

[Serializable]
class Class1: Hashtable
{
    public Class1(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        FieldInfo[] fields = this.GetFields(this);
        foreach (FieldInfo fieldInfo in fields)
        {
            Object obj = info.GetValue(fieldInfo.Name,fieldInfo.FieldType);
            fieldInfo.SetValue(this,obj);
        }
    }
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        FieldInfo[] fields = this.GetFields(this);
        foreach (FieldInfo fieldInfo in fields)
        {
            info.AddValue(fieldInfo.Name,fieldInfo.GetValue(this));
        }
        base.GetObjectData(info, context);
    }
    public Class1()
    {
    }
    protected int number;
    private int othernumber;
    public string text;

    public int OtherNumber
    {
        get
        {
            return othernumber;
        }
        set
        {
            othernumber = value;
        }
    }

    public int Number
    {
        get
        {
            return number;
        }
        set
        {
            number = value;
        }
    }

    private FieldInfo[] GetFields(object obj)
    {
        FieldInfo[] fields =
        obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

        return fields;
    }
}

Note that I’ve include the BindingFlags I’ve added to obtain the fields. This can be modified if other kind of filters are needed.

Friday, 27 April 2007

Identifying if the next/s control in z order hides a given control

This is a quite simple c# class that lets identify if for a certain control, there is another above that hides the control (partially or completely, depending on the option).

I've uploaded a sample project here: Z order sample project

Here is the ZOrder class code:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;

namespace ZOrderFunctions
{
///
/// Defines helper function for testing zorder relationships
///

// By Javier Alvarez, 27 april 2007
class ZOrder
{
#region GetWindow
private const int GW_HWNDNEXT = 2;
private const int GW_HWNDPREV = 3;
private const int GW_CHILD = 5;


[DllImport("User32.dll")]
private static extern IntPtr GetWindow(IntPtr hwndSibling,
int wFlag);
//Parameters
//hWnd
//[in] Handle to a window. The window handle retrieved is relative to this window, based on the value of the uCmd parameter.
//uCmd
//[in] Specifies the relationship between the specified window and the window whose handle is to be retrieved. This parameter can be one of the following values.
//GW_CHILD
//The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
//GW_ENABLEDPOPUP
//Windows 2000/XP: The retrieved handle identifies the enabled popup window owned by the specified window (the search uses the first such window found using GW_HWNDNEXT); otherwise, if there are no enabled popup windows, the retrieved handle is that of the specified window.
//GW_HWNDFIRST
//The retrieved handle identifies the window of the same type that is highest in the Z order. If the specified window is a topmost window, the handle identifies the topmost window that is highest in the Z order. If the specified window is a top-level window, the handle identifies the top-level window that is highest in the Z order. If the specified window is a child window, the handle identifies the sibling window that is highest in the Z order.
//GW_HWNDLAST
//The retrieved handle identifies the window of the same type that is lowest in the Z order. If the specified window is a topmost window, the handle identifies the topmost window that is lowest in the Z order. If the specified window is a top-level window, the handle identifies the top-level window that is lowest in the Z order. If the specified window is a child window, the handle identifies the sibling window that is lowest in the Z order.
//GW_HWNDNEXT
//The retrieved handle identifies the window below the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window below the specified window. If the specified window is a top-level window, the handle identifies the top-level window below the specified window. If the specified window is a child window, the handle identifies the sibling window below the specified window.
//GW_HWNDPREV
//The retrieved handle identifies the window above the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window above the specified window. If the specified window is a top-level window, the handle identifies the top-level window above the specified window. If the specified window is a child window, the handle identifies the sibling window above the specified window.
//GW_OWNER
//The retrieved handle identifies the specified window's owner window, if any. For more information, see Owned Windows.
#endregion

///
/// Tells if the control is hidden by other in the z order
///

/// Control to be checked
/// if true, a control is returned even if it is only partially hidden, if false, the control must be completely hidden
/// If there is a control above, reference to the control
public static Control IsHidden(Control sender, bool partially)
{
// Check preconditions
if (sender == null) throw new ArgumentException("IsHidden recieved null as parameter");

// 'Found a control' flag
bool ret = false;

// Return value
Control topControl = null;

// Point to the display area rectangle
Rectangle senderRect = sender.DisplayRectangle; //new Rectangle(sRect.X, sRect.Y, sRect.Width, sRect.Height); senderRect.Location.Offset(
senderRect.Offset(sender.Left, sender.Top);

// Iterate through higher z-order controls to see if any above the sender control
IntPtr currentHandler = sender.Handle ;
Control currentControl = null;
do
{
// Get next control
currentHandler = GetWindow(currentHandler, GW_HWNDPREV);

if (currentHandler != IntPtr.Zero)
{
// Get associated rectangle
currentControl = Control.FromHandle(currentHandler);
Rectangle currentRectangle = currentControl.DisplayRectangle;
currentRectangle.Offset(currentControl.Left, currentControl.Top);

// Select if fully contained or partially
if (partially)
{
ret = currentControl.Visible && currentRectangle.IntersectsWith(senderRect);
}
else
{
ret = currentControl.Visible && currentRectangle.Contains(senderRect);
}
// Point to control if it matches the condition
if (ret)
{
topControl = currentControl;
}

}

} while (!ret && currentHandler != IntPtr.Zero);

return topControl;




}
}
}




Build a sample form with three buttons and add the following (or alike) code to test:

public partial class Form1 : Form
{



public Form1()
{
InitializeComponent();
}

private void Test(object sender)
{
Control top = ZOrder.IsHidden(sender as Control, true);
if (top != null)
{
MessageBox.Show("Handle of control above is : " + top.Handle.ToString());
}
else
{
MessageBox.Show("This control is the topmost");
}
}

private void button2_Click(object sender, EventArgs e)
{
Test(sender);
}

private void button1_Click(object sender, EventArgs e)
{
Test(sender);
}

private void button3_Click(object sender, EventArgs e)
{
Test(sender);
}

private void Form1_Load(object sender, EventArgs e)
{
button1.Text = button1.Handle.ToString();
button2.Text = button2.Handle.ToString();
button3.Text = button3.Handle.ToString();
}
}

Tuesday, 28 November 2006

Winforms applications, threads and events

Ok here I go with my first entry with a very short sample I wrote for a mate to let him play with threads on winforms, you know... threads are funny!

Windows have a very special way to use threads on winforms as all the controls are bounded to the thread that creates them, so whenever you are going to modify a control´s property, you need to make sure you are doing from the right thread.

A common problem is that you launch a thread to perform async processing and at a certain point, the thread reaches some condition and launches an event.
In the event handler you want to modify some of the user interface properties but... you need to switch to the right thread. That´s where InvokeRequired and Invoke come to help.

InvokeRequired basically compares the thread identity to which the control you are testing is bounded with the thread identity of the running thread. If they are different, it returns true. In that
case, you must use Invoke to call a delegate in the right thread.

(Well it´s a little bit more complicated... Invoke can return false if the handle of the control hasn´t been created. If you are in that case, be careful of performing any operation as the control can be created bounded to the wrong thread. Check IsHandleCreated and CreateControl functions to learn more about it...)

By the way... playing with the delays you can realize that if the secondary thread finishes when the main thread is still busy, the invoke sentence is not executed till the main thread is finished. The reason for this is easy: The main thread is running continuosly a loop (you can see it in the call stack window) and the invoke sentence puts a special message to be consumed by that loop.
Only when the loop runs the next iteration, the invoke message is consumed.



Here it comes the mini-sample... copy paste it to a winforms code file to play with it




namespace win_threadDemo
{
public partial class Form1 : Form
{
private delegate void TextDelegate(string text);
private event TextDelegate EventDelegate;

public Form1()
{
InitializeComponent();
this.EventDelegate += new TextDelegate(this.OnEvent);
}

private void button1_Click(object sender, EventArgs e)
{
label1.Text = "";
label2.Text = "";
if (Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "Main thread";
}

Thread t = new Thread(new ThreadStart(SecondaryThreadOperation));
t.Name = "Secondary thread";
t.Start();
// Long running operation on main thread
Thread.Sleep(15000);
label2.Text = "Main thread finished";

}


private void SecondaryThreadOperation()
{
//Some long task
Thread.Sleep(10000);
//Raise event if any suscriber is present
if (this.EventDelegate != null)
{
this.EventDelegate("Secondary thread finished");
}

}

private void OnEvent(string text)
{
if (label1.InvokeRequired)
{
label1.Invoke(new TextDelegate(this.ChangeText), new object[] { text });
}
else
{
this.ChangeText(text);
}
}

private void ChangeText(string text)
{
label1.Text = text + " modified on " + Thread.CurrentThread.Name;
}

}
}