Monday, December 31, 2012

Passing Data Between Forms Redux

Almost exactly two years ago, I published the Passing Data Between Forms post. I have had numerous questions and comments about that post and now I’ve decided that it deserves an additional example.

In that post, I had an example (the 3rd one) that utilized Interfaces. In the example, we had a MainForm that passed a DataSet to Form1. Form1 then allowed the user to make some changes to the data in that DataSet and then we wanted to have MainForm automatically reflect those changes ... even while the user was still working in Form1. An interface worked well for that scenario. At the time, I wanted to keep the post simple so as not to confuse beginners. But, I really need to expand on that example and show how to accomplish this task using delegates/events.

So, without further ado (pun intended), here it is:

First, let's take a look at Form1. Minimally, you can implement this whole thing with a simple event, which uses standard EventArgs, as follows:

public class Form1 : Form
{
    public event EventHandler DataChanged;
    private CustomerDataSet oData;

    public Form1(CustomerDataSet dsCust)
    {
        this.oData = dsCust;
    }
    public void DoStuff()
    {
        // code to do stuff with this.oData
        // ...
        // and then fire the event if anyone has subscribed
        this.OnDataChanged(new EventArgs());
    }
    private void OnDataChanged(EventArgs e)
    {
        if (this.DataChanged != null)
            this.DataChanged(this, e);
    }
}

Then, the MainForm looks like this:

public class MainForm : Form
{
    private CustomerDataSet dsCustomer;

    // ...

    // then code elsewhere to instantiate and fill your data
    this.dsCustomer = new CustomerDataSet();
    // plus maybe other code to fill the dataset


    // ...

    // code to instantiate Form1, pass it the DataSet, handle the event
    Form1 oForm = new Form1(this.dsCustomer);
    oForm.DataChanged += new EventHandler(DataChanged);
    oForm.Show();

    public void DataChanged(object sender, EventArgs e)
    {
        // code here to do stuff with this.dsCustomer
    }
}

In this particular case, we don't really need EventArgs. Because we passed the DataSet into Form1 to begin with, we already know everything we need to know, namely the data that has changed will be the same DataSet that we passed into Form1. So, since we don’t need any EventArgs, we could create a custom delegate to use as our event handler. We will change our two forms like this:

Form1:

public class Form1 : Form
{
    public delegate void DataChangedEventHandler();
    public DataChangedEventHandler DataChanged;
    private CustomerDataSet oData;

    public Form1(CustomerDataSet dsCust)
    {
        this.oData = dsCust;
    }
    public void DoStuff()
    {
        // code to do stuff with this.oData
        // ...
        // and then fire the event if anyone has subscribed
        this.OnDataChanged();
    }
    private void OnDataChanged()
    {
        if (this.DataChanged != null)
            this.DataChanged();
    }
}

The only difference in MainForm is that the event handler doesn't need the usual parameters (object sender, EventArgs e), so change the DataChanged event handler to look like this:

// code to instantiate Form1, pass it the DataSet, handle the event
Form1 oForm = new Form1(this.dsCustomer);
oForm.DataChanged += new Form1.DataChangedEventHandler(DataChanged);
oForm.Show();

public void DataChanged()
{
    // code here to do stuff with this.dsCustomer
}

Another way of handling the event in the MainForm is to not even bother with the above DataChanged() method and use an anonymous delegate instead, so you could change the MainForm code to look like this:

// code to instantiate Form1, pass it the DataSet, handle the event
Form1 oForm = new Form1(this.dsCustomer);
oForm.DataChanged += delegate
{ 
    // code here to do stuff with this.dsCustomer
};
oForm.Show();

There are other things you can do when creating your own delegates and/or events and, in fact, I have a written a blog post about a DataAccess class that does some interesting things with anonymous delegates: DataAccess - Part III.

However, expanding on ideas for delegates and/or events is beyond the scope of this simple post. Perhaps in the future I’ll write something more extensive, but in the meantime, you can always start off with an MSDN article such as this one: Handling And Raising Events

Sunday, December 16, 2012

ComboBox Gotchas

This is pretty well-known for experienced Windows Forms developers, but I still see the problem frequently asked about on the forums. Typically, the questions will be something like:

  1. “Every time I make a different selection from my ComboBox, the row in my grid changes.”
  2. “I have two ComboBoxes on my Form, but they’re in sync. Every time a selection is made in  one, the selection changes in the other.”

So, what is it that they’re doing wrong? Well, the DataSource of a ComboBox cannot be in use by any other databound control on the Form … unless, of course, your intention is to use the ComboBox for navigation … but then, you wouldn’t be asking these questions!

It doesn’t matter if you are using an actual DataTable for your Combo’s DataSource, or if you’re using a BindingSource, the bottom line is that you cannot use the same object to databind other controls. How about a few illustrative examples, first with DataTable and then with BindingSource? In my scenario, I’ll use 3 controls, a DataGridview, a TextBox and a ComboBox. I want the DataGridView and the TextBox to be in sync. When I move through the grid, the value in the TextBox changes accordingly. The ComboBox, on the other hand, should behave independently.

Using DataTables as DataSource

First, let’s set up the databinding for the grid and textbox:

this.dataGridView1.DataSource = this.dtMyTable;
this.txtLastName.DataBindings.Add("Text", this.dtMyTable, "Code");

And now, in order to see how NOT TO bind the ComboBox, try the following code and notice what happens! 

// As we now know, by setting the ComboBox.DataSource to a DataTable that's already bound elsewhere
// moving through the Combo also affects the bound textbox and the grid. This is BAD CODE!!
this.cboDescription.DisplayMember = "Description";
this.cboDescription.DataSource = this.dtMyTable;

Well, ok, it’s bad. What can we do instead? We have two choices:

// Setting the DataSource to a DataView of the same DataTable works just fine
DataView dv = new DataView(this.dtMyTable);
this.cboDescription.DisplayMember = "Description";
this.cboDescription.DataSource = dv;

-OR-

// We could use a Copy of the original DataTable
this.cboDescription.DisplayMember = "Description";
this.cboDescription.DataSource = this.dtMyTable.Copy();

Either way gives you the correct results: when the user changes the selection in the Combo,  nothing at all happens to the grid or textbox.

Using BindingSources as DataSource

Getting the same results using BindingSources is similar. First, set up the binding of the grid and textbox:

BindingSource bs = new BindingSource();
bs.DataSource = this.dtMyTable;
this.txtLastName.DataBindings.Add("Text", bs, "Code");
this.dataGridView1.DataSource = bs;

And again, in order to see how NOT TO bind the ComboBox, try the following code and notice what happens!

// Now the Combo DataSource: As expected, using the same BindingSource doesn't work. BAD CODE
this.cboDescription.DisplayMember = "Description";
this.cboDescription.DataSource = bs;

And what can we do instead?

// A new BindingSource works fine
this.cboDescription.DataSource = new BindingSource(this.dtMyTables, null);

And here’s an interesting one to try:

// A new BindingSource based on the old BindingSource
// Yep! This one works too!
this.cboDescription.DataSource = new BindingSource(bs, null);

Binding the ComboBox

Now, there’s one more thing I’d like to explore. What do you code if you need to have the SelectedValue of the ComboBox be tied to the what’s being displayed in the grid (or perhaps elsewhere, say maybe a label). Previously, we have only set the Combo’s DataSource, but this doesn’t do anything with whatever the user has selected from the Combo. So now we want to databind it, as we’ve databound the grid and the textbox. Let’s say we have another control, a label, and we want it to reflect the chosen Description in the ComboBox. We’d need to bind the label and Combo to the same thing.

// Using the DataTable:
this.lblDescription.DataBindings.Add("Text", this.dtMyTable, "Description");
this.cboDescription.DataBindings.Add("SelectedValue", this.dtMyTable, "Description");

// Or, using the BindingSource instead:
this.lblDescription.DataBindings.Add("Text", bs, "Description");
this.cboDescription.DataBindings.Add("SelectedValue", bs, "Description");

Try either methodology. Select an item from the Combo and notice that the label changes to reflect that selection. Then, move between rows in the grid. You should notice the label changes then too. When on a different row in the grid, change the selection of the Combo again. When moving back and forth between rows in the grid, notice that the ones you changed with the Combo selection remain at that new value.

Sunday, October 28, 2012

Crowd Funding

Some of you may have heard of “Crowd Funding” or “Cyber Begging” or any of the other newest buzz words involving, basically, raising money online: sometimes for a good cause, sometimes to help start a business, sometimes for no reason except that you need money. We’ve all been there at some point in our life …

I’m unfortunately in that situation right now. Little to no income for 3 years now, while we try to start up a new business … it doesn’t take long before the savings account gets depleted! But, we've got a great product and one customer who loves it! It's only a matter of time before we get more customers. In the meantime, we need more cash. Here's our business website: Geneva Systems Group

Anyway, I’ve got a PayPal “Donate” button here on my blog site, that I’ve had since I started this blog. It sure would be nice if some of my many readers would take the time to just click that button. You don't even need a Paypal account to donate (Paypal will accept credit card donations although your credit card company may charge a fee).

I'm thinking of putting another PayPal button here, specfically for this funding campaign, but until I do please use the only one on the page.

Every little bit helps and I’d sure appreciate it!!!

XAML Intellisense

I’ve done a little here and there with WPF over the past few years. Nothing of production quality, but still a bit more than just “playing with it”. One of the things that bugged the hell out of me was that I couldn’t figure out how to get Intellisense to kick in while working with the XAML (I rarely use the designer). Lately I’ve been getting back into WPF a bit more deeply and when you start designing more complicated UI, you really need to have XAML Intellisense, otherwise you have to keep looking stuff up!

So, I Googled around for an answer and finally found something after many search attempts. And wow, it’s soooooo simple! Here’s where I found the answer, and I want to sincerely thank Fabrice for posting this: http://weblogs.asp.net/fmarguerie/archive/2009/01/29/life-changer-xaml-tip-for-visual-studio.aspx

Basically, what Fabrice says is to use the Source Code Editor rather than the XML editor. That’s it in a nutshell and it’s one of those forehead-slapping, duh, why-didn’t-I-think-of-that kind of things!

You can read Fabrice’s blog, but here are his 6 easy steps:

  1. Right-click on a XAML file in the Solution Explorer
  2. Select "Open With..."
  3. Select "Source Code (Text) Editor"
  4. Click on "Set as Default"
  5. Click OK
  6. You're done!

Sunday, September 02, 2012

A Generic WCF Proxy Class

A couple of years ago, when I first started using WCF, it seemed like a real pain in the you-know-what to add Service References to my app in order to consume WCF Services. I wanted a base Proxy class that I could extend to be used for any kind of ServiceContract. The key to writing this class was the use of generics Here’s what I came up with, after much trial and error (be sure you have using System.ServiceModel and using System.ServiceModel.Channels):

public abstract class ProxyBase<T> where T : class
{
    #region Declarations
    public ChannelFactory<T> Factory = null;
    public T proxy { get; set; }
    public string EndpointName { get; set; }
    private string m_Certificate;
    public string Certificate
    {
        get { return this.m_Certificate; }
        set
        {
            try
            {
                this.m_Certificate = value;
                if (this.m_Certificate.IsNotNullOrEmpty() && Factory != null)
                {
                    EndpointIdentity Identity = EndpointIdentity.CreateDnsIdentity(this.m_Certificate);
                    if (Identity == null)
                        Console.WriteLine("Identity Is Null");
                    else
                    {
                        Uri AddressUri = Factory.Endpoint.Address.Uri;
                        Factory.Endpoint.Address = new EndpointAddress(AddressUri, Identity);

                        // not sure, but probably have to remove old EventHandler before recreating the 
                        // proxy and recreating the Channel.
                        ((ICommunicationObject)proxy).Faulted -= new EventHandler(ProxyBase_Faulted);
                        proxy = Factory.CreateChannel();
                        ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
                    }
                }
            }
            catch (Exception ex)
            {
                Factory = null;
                proxy = null;
            }
        }
    }
    #endregion

    #region Constructors
    public ProxyBase() { }
    public ProxyBase(string endpoint)
    {
        // not the best error-handling, but good enough for now
        // TODO - make error-handling better
        //        Already handling faulted channels, but now need to do something for bad addresses?
        //        Because I *think* a bad address will cause an exception in the creation of the Factory.
        try
        {
            this.EndpointName = endpoint;
            Factory = new ChannelFactory<T>(endpoint);
            proxy = Factory.CreateChannel();
            ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error in Proxy for {0}, Endpoint: {1}\r\n{2)", typeof(T).Name, endpoint, ex.Message);
            Factory = null;
            proxy = null;
        }
    }
    public ProxyBase(string endpoint, string address)
    {
        // not the best error-handling, but good enough for now
        // TODO - make error-handling better
        //        Already handling faulted channels, but now need to do something for bad addresses?
        //        Because I *think* a bad address will cause an exception in the creation of the Factory.
        try
        {
            this.EndpointName = endpoint;
            Factory = new ChannelFactory<T>(endpoint);
            Factory.Endpoint.Address = new EndpointAddress(address);
            proxy = Factory.CreateChannel();
            ((ICommunicationObject)proxy).Faulted += new EventHandler(ProxyBase_Faulted);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Proxy for {0}, Endpoint: {1}, Address: {2}\r\n{3}", typeof(T).Name, endpoint, address, ex.Message);
            Factory = null;
            proxy = null;
        }
    }
    #endregion

    #region Methods
    public void Close()
    {
        if (proxy != null)
            ((IChannel)proxy).Close();
        if (Factory != null)
            Factory.Close();
    }
    #endregion

    #region Events
    private void ProxyBase_Faulted(object sender, EventArgs e)
    {
        Console.WriteLine("Proxy for {0}\r\n{1}", typeof(T).Name, ((IChannel)proxy).State.ToString());
        ((ICommunicationObject)sender).Abort();
        proxy = Factory.CreateChannel();
    }
    #endregion
}

Seems pretty simple. Notice that it’s an abstract class. You must sub-class it in order to use it. OK, so how do we construct the sub-class? Very simple also. First, you must have a few Interfaces defined, as you would normally have for any WCF service. Here is what I’m going to use for my example:

[ServiceContract(Namespace = "http://MyCompany")]
public interface IMessageService
{
    [OperationContract(IsOneWay = true)]
    void ProcessMessage(IMessage message);
}

[ServiceContract(Namespace = "http://MyCompany")]
public interface ISynchronousMessageService
{
    [OperationContract]
    bool ProcessMessage(IMessage message);
}

public interface IMessage
{
    string MessageToSend { get; set; }
    string MessageReceived { get; set; }
}
public class MyMessage : IMessage
{
    public string MessageToSend { get; set; }
    public string MessageReceived { get; set; }
}

All WCF Services need to have a ServiceContract and OperationContract, so there they are. I’ve also got an interface defined for the Messages I’m going to send, plus a MyMessage class that implements that IMessage interface.

Next, here is what my sub-classed Proxies might look like:

public class SynchronousProxy : ProxyBase<ISynchronousMessageService>, ISynchronousMessageService, IDisposable
{
    #region Constructors
    public SynchronousProxy(string endpoint) : base(endpoint) { }
    public SynchronousProxy(string endpoint, string address) : base(endpoint, address) { }
    #endregion

    #region Methods
    public virtual bool ProcessMessage(IMessage message)
    {
        try
        {
            if (proxy != null)
                return proxy.ProcessMessage(message);
            else
                return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception, ProcessMessage\r\n{0}", ex.Message);
            return false;
        }
    }
    public void Dispose()
    {
        this.Close();
    }
    #endregion
}
public class Proxy : ProxyBase<IMessageService>, IMessageService, IDisposable
{
    #region Constructors
    public Proxy(string endpoint) : base(endpoint) { }
    public Proxy(string endpoint, string address) : base(endpoint, address) { }
    #endregion

    #region Methods
    public virtual void ProcessMessage(IMessage message)
    {
        try
        {
            if (proxy != null)
                proxy.ProcessMessage(message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception, ProcessMessage\r\n{0}", ex.Message);
        }
    }
    public void Dispose()
    {
        this.Close();
    }
    #endregion
}

And now, how do I actually use these proxy classes? You’d have the usual WCF stuff defined in the .config in the endpoint in the systemServiceModel tags:

  <system.serviceModel>
    <client>
      <endpoint name="MyEndpoint"
          address="net.tcp://MyComputer:666/MyMessageService"
          binding="netTcpBinding" bindingConfiguration="netTcpConfig"
          contract="MyApp.IMessageService"/>
    </client>
  </system.serviceModel>

And then in your code, you’d call the WCF service like this:

using (Proxy proxy = new Proxy("MyEndpoint"))
{
    MyMessage message = new MyMessage();
    message.MessageToSend = "MyTestMessage";
    proxy.ProcessMessage(message);
}

Wow, that’s pretty easy, isn’t it? No need to add ServiceReferences or anything like that. All you need to know are the Interfaces that the Services use and you’re good to go!

Saturday, August 11, 2012

MSDataSetGenerator Gone Wild

As regular readers of my blog may know, I’m big into Typed DataSets (but not the TableAdapters that can sometimes get generated with them. See my blog posts about this topic, starting with this one: http://geek-goddess-bonnie.blogspot.com/2010/04/create-xsd.html).

Two months ago I ran into a problem when the MSDataSetGenerator went crazy. I asked questions about it on the Forums and ended up discovering a workaround for it myself. Then, earlier this week it happened again and I couldn’t remember what my workaround was!!  I looked for my post from 2 months ago on the Forums and my workaround saved the day. I figured it was time to write a blog post about it.

Here’s an excerpt from my original forum post about what was happening:

In the past, I've not had any problems generating a Typed DataSet from my .xsd. (I'm using VS 2010). The project is set to .NET 4, but the MSDataSetGenerator refuses to generate TypedTableBase in the  Designer.cs file (still using DataTable).  I've tried everything ... deleting the Designer.cs, right-clicking the .xsd in the solution and "Run Custom Tool", deleted MSDataSetGenerator from the CustomTool property and then adding it back in,  etc.etc.etc.   Nothing works, it keeps generating DataTables  instead of the proper TypedTableBase.

The weird thing is that, as far as I know, the only time it's supposed to generate DataTable is if your project targets .NET 3.0 or lower. .NET 3.5 and above should generate TypedTableBase. But that’s not what was happening. But I finally figured it out … here’s my “Eureka” post from the forum:

Holy cow! This is strange! I typically add a DataSet by doing the following:

  1. Copy an existing .xsd file to my project's folder.
  2. Right-click the project in Solution Explorer and "Add Existing", choosing the .xsd
  3. Add the MSDataSetGenerator to the Custom Tool property if necessary.
  4. Generate the Typed DataSet

... I've been doing it this way for years (but haven't always been paying attention to what gets generated, because I haven't typically used LINQ with the DataSets until recently).

Someone mentioned to me that I should try adding DataSets a different way. Instead of "Add Existing", I should "Add New Item" and choose a DataSet item. Then I can copy/paste the xml into it. I tried that in my current problem project and guess what ... it generated the TypedTableBase!  And, lo and behold, the DataSet that refused to generate TypedTableBase was now doing it correctly too!!  Weird!!

So, I decided to test it in a brand new project. I closed the solution (but did not close VS). Created a new solution/project, copied an .xsd file, "Add Existing", generate ... still TypedTableBase (I was expecting it to be DataTable, since I didn't "Add New Item", DataSet). Hmmm ... maybe it was because I didn't start with a fresh Visual Studio? I shut it down, started up VS again, went through the process a second time with a brand new solution and created the DataSet with "Add Existing" ... this time ... DataTable, as I now expected it to do.

And again, as soon as I did "Add New Item", DataSet ... both DataSets again generated TypedTableBase.

But wait ... there's more! As soon as I shut down Visual Studio and started it up again, the DataSets again revert to generating DataTables instead of TypedTableBase (until I "Add New Item", DataSet, then it's fine again).

Sounds like a major bug to me .... anyone else see this behavior?

UPDATE (two years later, 12/30/2014):
I have been meaning to update this blog post ever since a reader commented with a much better workaround to the bug. Not everyone reads comments, so this great idea may have been missed by some. Here is the comment, written by Anonymous:

If you open up Visual Studio (2008 in my case) and you have not yet opened any xsd dataset in a *graphical* designer, the custom tool will generate the designer code the *old* way (derived from a normal DataTable). After you open an xsd - any xsd - for the first time in a graphical designer, from that point forward the custom tool will generate the designer code the *new* way (derived from TypedTableBase).

Just remember to *not* make your updates in the graphical designer, just open it and then close it. And that only has to be done once (each time you open a new instance of Visual Studio).



Saturday, April 14, 2012

Forms Handler

I frequently see forum questions about how to handle/manage an app that uses many Windows Forms (when you’re not using MDI forms). It’s pretty simple really if you use a custom FormsHandler. This is something I wrote years ago and it still works just fine. It could probably stand to be updated a bit, like instead of using an ArrayList, use a List<Form> … but I’ll leave that as an exercise for the reader.

First the FormsHandler class. Notice that it uses only static methods, so the class never needs to be instantiated.

using System;
using System.Collections;
using System.Windows.Forms;

namespace MyNameSpace.MyClasses
{
    public class FormsHandler
    {
        #region Declarations
        private static ArrayList list = new ArrayList();
        #endregion

        #region Methods
        public static void Add(Form o)
        {
            Form oForm = Find(o);
            if (oForm == null)
            {
                oForm = o;
                list.Add(o);
            }

            oForm.Show();
        }
        public static Form Find(Form o)
        {
            foreach (Form x in list)
            {
                if (o.GetType().Equals(x.GetType()))
                    return x;
            }
            return null;
        }
        public static void Remove(object o)
        {
            list.Remove(o);
        }
        public static bool Close()
        {
            int nCount = list.Count;
            while (list.Count > 0)
            {
                ((Form)list[0]).Close();
                if (list.Count == nCount)
                    return false;
                else
                    nCount = list.Count;
            }

            return true;
        }
        #endregion

        #region Properties
        public static ArrayList List
        {
            get { return list; }
        }
        #endregion
    }
}

Whenever you open a form, no matter where you open it from, all you do is add it to the ArrayList, like this:

Form oForm = new MyForm();
FormsHandler.Add(oForm);

All your Forms should have this in their ClosedHandler() method:

protected virtual void ClosedHandler(object sender, EventArgs e)
{
    FormsHandler.Remove(this);
}

When you close your Main Form, you want all others to Close (but to execute their own Closing methods) ... do it like this:

// This is a menu item that exits the application

private void menuItem4_Click(object sender, System.EventArgs e)
{
    System.ComponentModel.CancelEventArgs ee = new CancelEventArgs();
    this.ClosingHandler(sender, ee);
}

// This is the ClosingHandler that will execute normally if you close the app
// by clicking on the "X"

private void ClosingHandler(object sender, System.ComponentModel.CancelEventArgs e)
{
    if (!FormsHandler.Close())
        e.Cancel = true;
    else
        Application.Exit();
}

Notice that the FormsHandler.Close() method will iterate through each Form contained in its list and attempt to close that Form. If it can successfully close all the Forms, then it will return true, otherwise it will return false.

Thursday, February 16, 2012

WCF And Certificate Security

Our application is a messaging system, relying on WCF to send messages around to other computers. We have our WCF services hosted as a Windows Service. The predominate scenario for the use of this system would be on computers within a domain or series of trusted domains and so Windows security seemed to be the easiest way to implement this.

For both netTcpBinding and wsHttpBinding, no security tags were needed, because the defaults were what we wanted. The default for netTcpBinding is Security=”Transport” and clientCredentialType=”Windows”. The default for wsHttpBinding is Security=”Message” and clientCredentialType=”Windows”. This works great between computers on the same domain or on trusted domains.

Well, as luck would have it, our first customer doesn’t trust anybody. The various agencies that needed to “talk” together, don’t have trust between their domains and refuse to grant any trust. So, we were back to square one with trying to figure out how best to handle the security with a deadline looming in 4 short weeks!

We decided that Certificates were the way to go, but  trying to find out how to implement them was a nightmare! Google all you want, but all you’ll find are incomplete examples. We struggled with this for a week. Every time we found something promising, and tried to implement it, there was always some important piece left out of the puzzle and nothing worked. Finally, Gary found this blog:

http://notgartner.wordpress.com/2007/09/06/using-certificate-based-authentication-and-protection-with-windows-communication-foundation-wcf/

Wow! Everything worked! Finally! No missing puzzle pieces! Our thanks go out  to Mitch Denny for his very complete and informative blog post!