Wednesday, April 7, 2010

Switch statements

In VB there was Select Case. In C# there is the switch statement.

The following is best practice on how you should handle cases that do
the same logic when hit.
using fall through on the case:

int x = 1;
switch ( x )
{
case 1:
case 2:
/* code here */
break;
case 3:
/* code here */
break;
default:
break;
}

The following while doable should not be used because it promotes
unreadable code, adding to complexity and potential for bugs:
Or use goto case statements:

int x = 1;
switch ( x )
{
case 1:
goto case 2;
case 2:
goto case 5;
break;
case 3:
/* code here */
break;
case 4:
goto case 2;
break;
case 5:
/* code here */
break;
case 6:
/* code here */
break;
case 7:
goto case 5;
break;
case 8:
/* code here */
break;
case 9:
goto case 2;
break;
default:
break;
}

How to use the dispatcher to run a new thread and how to make calls back to ProgressBar from Dispatcher

I got this technique from this link:
http://windowsclient.net/learn/video.aspx?v=57027

Its related to using the BackgroundWorker, apparently BackgroundWorker calles Dispatcher, but this example is so simple that I like it.

        private void DoSomething()
        {
                    new Thread(
                      delegate()
                      {
                        Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate { progressBar.IsIndeterminate = true; }, null);
                        LongRunningProcess();
                        Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate { progressBar.IsIndeterminate = false; }, null);
                      }
                    ).Start();
        }

Tuesday, April 6, 2010

How to use a ProgressBar in WPF using the BackgroundWorker class

- Have a xaml file with a progressBar called "progressBar" and a button called "button".  I called my project ProgressBar.  My window is also called ProgressBar instead of Window1.
- The key parts of the file below are:
    1.  create a BackGroundworker object.
    2.  Add the DoWork and RunWorkerCompleted events to the constructor of your function
    3.  Implement the DoWork event of the background worker
    4.  Implement the RunWorkerCompleted event of the background worker
    5.  Call the RunWorkerAsync function of the background worker.  This calls the DoWork function.  When its done the RunWorkercompleted function is called.  You can have DoWork return you something - in my example its a string but it could be any object.
    6.  You set the progressBar.IsIndeterminate to true in the click event and you set it to false in the Runworkercompleted function
  
That's pretty much it. 
=====================================
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Input;

namespace ProgressBar
{
    public partial class ProgressBar : Window
    {
        private BackgroundWorker progressBarWorker;

        public ProgressBar()
        {
            InitializeComponent();

            // Create a Background Worker
            progressBarWorker = new BackgroundWorker();

            // Enable support for cancellation
            progressBarWorker.WorkerSupportsCancellation = true;

            progressBarWorker.DoWork +=
                new DoWorkEventHandler(progressBarWorker_DoWork);
            progressBarWorker.RunWorkerCompleted +=
                new RunWorkerCompletedEventHandler(progressBarWorker_RunWorkerCompleted);
        }

        private void progressBarWorker_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
            this.Cursor = Cursors.Arrow;

            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }

            button.Content = "Start";

            // Reset the ProgressBar's IsInderterminate
            // property to false to stop the progress indicator
            progressBar.IsIndeterminate = false;

          // You can even get a return value from the progressBarWorker using e.result
            string strval = (string)e.Result;
            //do something with strval
            MessageBox.Show(strval);
        }

        private void progressBarWorker_DoWork(
            object sender, DoWorkEventArgs e)
        {
            for (int i = 1; i <= 500; i++)
            {
                if (progressBarWorker.CancellationPending)
                    break;

                Thread.Sleep(50);
            }
            //You can return something from the Worker
            e.Result = "some str";
        }

        private void button_Click(
            object sender, RoutedEventArgs e)
        {
            if (!progressBarWorker.IsBusy)
            {
                this.Cursor = Cursors.Wait;

                // Set the ProgressBar's IsInderterminate
                // property to true to start the progress indicator
                progressBar.IsIndeterminate = true;
                button.Content = "Cancel";

                // Start the Background Worker
                progressBarWorker.RunWorkerAsync();
            }
            else
            {
                progressBarWorker.CancelAsync();
            }
        }

    }
}

Thursday, April 1, 2010

Advantages of routed events

From - http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-routed-events-in-wpf/

The routed notification pattern has many benefits.  One very important benefit of routed events is that a high-level visual element in a UI need not explicitly hook the same event on all of its descendants, such as MouseMove.  Instead it can hook the event on itself, and when the mouse moves over one of its descendants, the high level element will be notified appropriately.

Another important advantage of routed events is that elements at all levels of the visual tree can execute code in response to events of their descendants, without expecting the descendant to notify them when the event fires.   An ancestor element which hooks a tunneling event can even prevent its descendants from ever receiving both the tunneling and bubbling events at all (although it is possible for an element to demand that it is notified of the event, regardless of it is handled or not).


Call and Raise Events in WPF from Child Control to parent window

I know there are a lot of documentation on routed events in wpf, and examples. For example see http://www.codeproject.com/KB/WPF/BeginWPF3.aspx

Either way, for some reason I just wasn't getting it. It took a couple of hours of reading and trying, but I was finally able to figure it out. Below is my explanation.

Just say you have a MainWindow and in it you have a custom control, called ControlHome. In your ControlHome you want to raise an event and have it caught by the MainWindow. Back in WinForms you would define the event in the control, raise it in the control and then "catch" it in the MainWindow. The idea is somewhat similar in WPF, but you have to do something called Routed Events, and with Routed Events you can do a lot more, but I'll just focus on the scenario of Child Control to MainWindow.

In the Child Control (called ControlHome) you need to create the event
public static RoutedEvent StartProgressBarEvent;
(I've seen a lot of documentation where it was made read-only, but when I did this, I get an error when I define it in the Constructor so I removed the readonly statement.

In the constructor of the child control you register it like this:

StartProgressBarEvent = EventManager.RegisterRoutedEvent("StartProgressBar", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(ControlHome));

I specified it to "Bubble" which means it goes up the tree. I name "StatusProgressBar" will be used later on. The type is RoutedEventHandler, and ChildControl is the control that is going to raise the event

You also need to add the handler for the Event like this to the child control:
public event RoutedEventHandler StartProgressBar
{
add {base.AddHandler(StartProgressBarEvent, value);}
remove {base.RemoveHandler(StartProgressBarEvent, value);}
}

Lastly when you want to raise the event you can do so like this:
RoutedEventArgs e1 = new RoutedEventArgs(StartProgressBarEvent);
RaiseEvent(e1);

So to review, in the Child Control, you create it, register it and add the handler for it, and raise it when you want to. Now your child control has this event registered to it, so a parent window can just call it. For example, the button has an event called Click, so a parent event can define what will happen when a user clicks on the button.

In the parent window, in the ChildControl.xaml file, where I added the control to the file, I now say that the even StartProgressBar will be handled by the function "StartProgressBar"

<local:ChildControlx:Name="ChildControl1" StartProgressBar="StartProgressBar"/>

In the file ChildControl.xaml.cs, I define the StartProgressBar function, like this:
private void StartProgressBar(object sender, RoutedEventArgs e)
{
// Do something here
}

That's it. The RoutedEvents also allow you to tunnel events down the tree, but I won't get into that right now.