Monday, May 28, 2007
For a number of reasons which include interface, ease of customizability and others, I've decided to move my blog to http://drisszouak.spaces.live.com
I hope you'll join me with this new location. Please note that the best articles from here have been reposted there with the category of REPOST: Technical.
Sunday, April 15, 2007
Recently I purchased a Maxtor Shared Stored II - 1TB network attached storage device. Good simple device. However, for a reason that baffled me I couldn't get the EasyManage software to see the device for love or money. I was able to get another computer I have to see it with no effort, and thus a frustrating search for the answer began.
The answer was the VPN Client I have installed on the first machine, which is by Checkpoint. Even when not connected, it puts in place a security policy that prevents the Maxtor EasyManage to work. All you need to do is right click on the VPN icon in the XP tray, and select Disable Security Policy and EasyManage will work. Before you VPN in, however, you should flip it back on if your VPN software doesn't automatically.
Wednesday, March 28, 2007
I'm running into this a lot lately with developers who are using EntLib for the first time, particularly the Data Access block.
You create a new project, you use the Enterprise Library configuration tool, you have your first db line like
Database db = DatabaseFactory.CreateDatabase("MyConnectionString");
and you get an exception that is talking about some ObjectBuilder version 1.0.... that cannot be found, type initializer exception, etc. You're completely lost, you lose faith, you Google it but don't find any helpful answers.
My experience is that this tends to happen when you've had AppSettings already in your .config file. The Configuration Tool seems to insert an invisible character or something into the configuration file that makes the sections it needs, unusuable, and thus gives you this completely unhelp error, trying to tell you that it cannot read the configuration info.
The best thing to do is create a brand new configuration file, copy and paste everything from your "broken" .config file to the new one. Delete the old one, use the new one, and everything should be fine. The "Invisible character" will not get copied, fortunately.
Hopefully if you have been banging your head against your desk with this issue you've been able to find this post, and it has worked for you. If it didn't, drop me a line, I'll see if I can help.
Tuesday, February 20, 2007
The Microsoft Enterprise Library for .NET, whether for 1.1 or 2.0, is a good thing in general. The Data Access application block definitely adds value, but there are things that aren't clear. One of those things is how to properly use transactions with it. The way you could use transactions with ADO.NET 2.0 doesn't seem to properly work, depending on how your doing it, with the Enterprise Library. This can give you the error "Transaction object not associated with Connection Object", at which point you pull your hair out because you just assigned it.
Here's some sample code to help you through
// Connect to the database
Database db = DatabaseFactory.CreateDatabase("MyDatabaseString");
DbConnection con = db.CreateConnection();
DbTransaction trans = null;
try
{
con.Open();
trans = con.BeginTransaction();
DbCommand com = db.GetStoredProcCommand("SomeStoredProcedure");
// Example of adding an in parameter
db.AddInParameter(com, "p_MyParam", DbType.String, somePassedInVariable);
// All of the needed Executes allow you to pass in a transaction
db.ExecuteNonQuery(com, trans); // <== Notice that this is called on the DB and not on the command object. This threw me for a loop the first time
trans.Commit();
}
catch (Exception ex)
{
// Handle the exception however you want
trans.Rollback();
}
finally
{
// Always close your connections.
con.Close();
}
Every now and then I get emails asking me about this problem because I once posted asking the question. If you have any questions regarding this, feel free to ask.
Friday, February 09, 2007
So you have Visual Studio Team System, and you opened up Team Explorer, selected Source Control, found the project you want, double click it, and select the wrong place for the files to go (local folder). You want to fix this, but where? How? There's seemingly no logical place where you go and do this.
The thing to remember with Visual Studio Team System is that there is this concept of WorkSpace, which is not intuitive or really clearly defined in my humble opinion, thus it tends to be ignored by developers until there's a problem.
The answer is this:
1. Go to the Source Control Explorer
2. In the tool bar for Source Control Explorer, open the list of Workspaces (i.e. clikc on the little down arrow of the drop down list), select Workspaces.
3. Select your active workspace and click edit.
4. Voila! Now click on the folder that you want to change, click OK on everything, and your done.
Friday, November 03, 2006
If you're like me using Team Foundation Server, aka Visual Studio Team Edition aka Team System, has had its bumps and there isn't a lot out there to help you figure out some issues. As I recall them, or encounter them, I'll try to post them here.
Today's big issue was not being able to creat a build type because I was told that the directory (C:\temp in my case) was in use by another work space. Okay, so after searching, I finally found that the drop down in the Source Control Explorer view that listed my workspace had a "Workspaces" option which allowed me to manage them. So I deleted the old ones. This did nothing.
Then I searched online and found the command line (very useful but badly documented) tf command (use the VS.NET Command Prompt from the Start menu). tf workspaces listed all of the workspaces currently in use. This didn't help either.
Finally I realized that it must be because of the seurity approach we took and something I must have done with that. See, we decided to be good digital citizens and not grant our everyday AD accounts full administrator privileges for everything in Team System, instead having a special Admin for creating new projects. Sounds like a great idea. Problem is when I did a Run As on my VS.NET with my Admin account and did a Get Latest, it created a workspace that locked my C:\temp directory. I didn't run into this as a problem until I tried to create a build type for my project, or any project, that my regular account had access to.
What I needed to do was launch VS.NET as my Admin account, go to the Source Control Explorer, select workspaces from that drop down of the workspaces, delete the workspace for my Admin account that was on my machine (but leaving the other ones that were valid on other machines), then closed VS.NET and launched it with my regular account. Problem solved.
Wednesday, November 01, 2006
For a recent project I had to use Oracle though we had initially been lead to
believe that it would be SQL Server. This provided a good
learning experience in getting to know Oracle. It's been more
than 7 years since I've used Oracle, and thus never used it with .NET. At
first I thought it would be pretty straight forward, and thus I didn't
anticipate losing DAYS instead of hours of time in getting things to work and
wrapping my head around Oracle's view of the world. While we used the
Microsoft Enterprise Library for .NET it doesn't completely shield you
from the different databases, requiring you to actually make DB specific code,
which seems to almost defeat the purpose of using it at times.
The purpose of this entry is not to itemize all of the differences between SQL
Server and Oracle but rather to address some of the key ones that hit me when
we started using it.
The Tools
Oracle 10g allows you to write .NET embedded code, just like SQL Server 2005.
This article is not about that. We didn't use it though it looks neat. My pain
and frustration started at the conceptual level.
I started with the personal edition of version 10g is available for download,
and installs straight forward enough. I say started with. In SQL Server land,
we're used to the Enterprise Manager. You can do, as a database developer
pretty much everything you need to with it. As a software developer, you can
use SQL Profiler to see what your actually sending to your SQL database, and
thus your life is complete. You can create tables, views, users, stored
procedures, and figure out what you're sending versus what you think you're
sending, nice and cleanly.
Welcome to Oracle, life is different. To start with, the web tool that Oracle
comes with allows you to do certain things well and other things not at all,
or at least I couldn't figure them out in the time provided. For example, I
could export my scheme and create users well enough, but I ran into errors
creating tables. Yes, that's right, using the web forms it provided, I ran
into errors. Doing what seemed to me to be pretty straight forward stuff.
It was at this point that I returned to the Oracle website to try and find a
better tool, and I found one in Oracle's SQL Developer tool. A Java based tool
that allows you to have most of the “Developer's side of SQL Enterprise
Manager” functionality. Creating tables were quicker and easier, and while the
tool has a couple of bugs, it quickly became a staple of the project. Between
the SQL Developer tool and the Oracle web tool, it did most of what we needed,
except for things like data extracts and some bugs in the tools prevented us
from knowing or fixing, issues. So, enter Toad. In the Oracle world, Toad (by
Quest Software) is a “must have“ tool that I remember for the last time I used
Oracle. After you download it, and open it for the first time, you will likely
scream in horror at the user interface.
As a SQL Server guy, I now had 3 tools that I needed to use to try and get
done what I would usually do in Enterprise Manager. The Oracle ADO.NET
Provider went from beta to release during our project, but I'm not a fan of
using Visual Studio for database work anyway, fyi.
Lastly, we used the .NET 2.0 Enterprise Library for our data access figuring
that it would allow us codeless flexibility between SQL Server and Oracle,
which after a couple of rounds of refactoring of our approach, ended up being
going in and changing :s to @s. I'll explain below.
Some Conceptual Differences
While the declared types are different for variables and table columns, the
real differences started showing up as Packages, Sequences, Cursors and stored
procedure system.
Stored Procedures
In SQL Server you create a stored proc, set the permissions and you're done.
In Oracle, you really are supposed to put your stored procedures in packages.
Packages conceptually containers for your stored procedures, you can think of
them as either a folder or namespace because they are like both. The full name
of your stored procedure includes the package name. Packages have two parts to
them, the specification and the implementation. A C++ minded person would say
the .h file prototype of the class and the .cpp with the content, a COM person
might think Interface and implementation.
At first you think that you're going to have to repeat yourself, and grumble
about Oracle for a couple of minutes. Then you realize that this allows you to
write the specification, i.e. all the method headers you want to call. For
example, procedure GetSummaryRecords ( param1 as int, ...). This allows you to
come back later, or in my project's case have someone else come back later,
and finish it off. I was able to specify what I needed in the specification
section and allow someone who was much more knowledgable than me do the actual
implementation and arrange the tables and views to support it as they saw fit.
Now an interesting thing to know when you are defining or implementing your
stored procedures is that all variables only require the type, i.e. if it's a
varchar 255 you only state varchar in the parameter declaration. Why? I don't
know, Oracle assumes that you know what you're doing. Of course in SQL Server
we have to precisely state what every length of every variable is in our
stored procedures. This little difference causes significant head scratching
when you try to take your stored procedure from one system to the other,
suffice it to say.
Unfortunately we found that we needed Toad and SQL Developer to properly
create our strored procedures, debug them, recompile them, etc. Strange, and
there's probably a way to only use one of the tools, but that's how it was for
my maiden voyage on the implementation side so some hair met its end at the
foot of my laptop.
Another conceptual difference in dealing with stored procedures is that if we
wanted to return data SQL Server style, we either had to create temporary
arrays/tables, populate them, and then send them back OR send back a cursor.
Suffice it to say that the Enterprise Library does not make this "invisible",
at least from none of the examples we found or any of our experiments, or the
documentation for that matter. Nothing worked properly or as expected. At one
point due to time constraint we decided to go with direct selects against
views for reading data and stored procedures for everything else. This also
works well if you need to separate the identities used for reading vs.
writing, as some customer security needs can require.
Sequences and Seeds
In SQL Server we mark a column as being sequenced, and it will generate a
number every time an insert is done. We do this regularly for IDs for tables.
In Oracle, things are different in two regards. Firstly, there is a Sequence
object in SQL, just like a table or a stored procedure. You have to define
your sequence object. The cool thing is that you can get the current value and
move it to the next value very easily, but on the other side, you have do
to things a bit more manually. Whereas for a SQL Server insert statement
you would not provide the ID because it will have a value set for you, in
Oracle you do provide the ID because you are the one effecitvely setting it,
using the mySequence.NextVal as the value you set the ID to.
Summary
These are not all of the differences but just some of them that me and my team
encountered when we had to use Oracle recently after expecting to use SQL
Server, and near the end of the project being asked to flip everything to SQL
Server. It was a good lesson in understanding the conceptual and programmatic
differences between Oracle and SQL Server, and hopefully if you're about to go
down this road or are a bit lost on it, this posting will help.
Saturday, October 14, 2006
Over the past couple of months I've been working furiously on a couple of projects, and now I need to start taking some of those learnings and putting them here on the blog.
More to come shortly...
If you're wondering if this is the same Driss Zouak who presented at Code Camp in Montreal, yes it is.
Sunday, July 02, 2006
I was working with a customer a couple of months ago where they were repeating code again and again, for every business entity, so that each business entity had the same base set of persistance methods:
- RetrieveById
- Save
- CreateNew
Before you ask, there lots of reasons why it had to be done this way and was done this way, none of which I'm really supposed to talk about, but suffice it to say that we all occasionally run into a situation where we want a bunch of classes to have the same static methods without recoding this every time and then needing to fix bugs in all of them when we find something. There's a way to use generics to get this effect, this “inheritance” however there is no overriding as such.
The example I'm using below is based around the idea of data persistance, one entity is a Desk and another is a Student. Each has its own PersistanceManager class. I'm not saying this is a great approach to take, but it is easy enough to explain with this that you should see how it is relevant to your own scenarios.
// This interface ensures that the class is able to be populated from a provided datarow and includes an Id property.
public interface IRowPopulatable {
Int32 Id
{
get;
set;
}
void PopulateFrom(DataRow row);
}
// This class represents a Student, though it is mostly empty for purposes of this article.
public class Student : IRowPopulatable
{
protected Int32 _id;
public Int32 Id
{
get { return _id;}
set { _id = value; }
}
// The PopulateFrom method in this class is empty as it doesn't matter relative to the article
public void PopulateFrom(DataRow row)
{
return;
}// PopulateFrom
}// Student
// This class represents a Desk, though it is mostly empty for purposes of this article, it has some differences from the Student.
public class Desk : IRowPopulatable
{
protected string _styleName;
protected Int32 _id;
public Int32 Id
{
get { return _id; }
set { _id = value; }
}// Property ID
public string StyleName
{
get { return _styleName; }
set { _styleName = value; }
} // Property StyleName
public virtual void PopulateFrom(DataRow row)
{
return;
}// PopulateFrom
public Desk() {
_id = -1;
_styleName = string.Empty;
}// Desk Constructor
}// Desk
// This is the main important class, the generic class. It uses a generic T, requires that the type T implement the interface IRowPopulatable simply to allow the static RetrieveById class to be able to be implemented once, generically. The new() requirement is because of the T result = new T().
public class PersistanceManager where T : IRowPopulatable, new()
{
public static T RetrieveById(Int32 id) {
// Defensive check of the id parameter not provided for simplicity
DataTable dt = new DataTable();
// Fake Data Retrieval populating dt with a datatable
T result = new T();
result.PopulateFrom(row);
return result;
}// RetrieveById
public static void Save(T entity)
{
}// Save
}// PersistanceManager
// This class is an example of a PersistanceManager that focuses exclusively on Desk. Note that it has no code other than a default constructor, which is not needed but is provided to illustrate that there is no code missing. The DeskPersistanceManager automatically has a Save and a RetrieveById static method.
public class DeskPersistanceManager : PersistanceManager
{
// The DeskPersistanceManager now has a RetrieveById method that returns
// a desk with no addition code
public DeskPersistanceManager()
{
}// DeskPersistanceManager
}// DeskPersistanceManager
// This class is an example of a PersistanceManager that focuses exclusively on Student. Note that it has no code other than a default constructor, which is not needed but is provided to illustrate that there is no code missing. The StudentPersistanceManager automatically has a Save and a RetrieveById static method. However as you would expect with generics, StudentPersistanceManager and DeskPersistanceManager do not have a common parent from which they inherit.
public class StudentPersistanceManager : PersistanceManager
{
// The StudentPersistanceManager now has a RetrieveById method that returns
// a student with no addition code
public StudentPersistanceManager()
{
}// StudentPersistanceManager
public static new void Save(Student sampleStudent)
{
// Do my own thing
return;
}
}// StudentPersistanceManager
With all of this code providing the interface, the two entities, the generic 'base' PersistanceManager and the 2 entity-specific PersistanceManagers we can now do the following
class Program
{
static void Main(string[] args)
{
Desk sampleDesk = DeskPersistanceManager.RetrieveById(5);
Student sampleStudent = StudentPersistanceManager.RetrieveById(3);
}// Main
}// Program
When you look at the Intelli-Sense for DeskPersistManager and StudentPersistanceManager you see the RetrievebyId which is specific to them, i.e. one returning Desk and the other Student respectively. Both have also a Save method, as expected.
The purpose of this technique is to allow you to have a means for avoiding recoding static methods again and again between classes for shared purposes. It does not allow you to have a defined interface, or anything, that would then allow you to iterate over multiple classes using them polymorphically as some common parent because they don't have a common parent. Remember, in .NET List and List do not have a common parent of List, they are effective ListInt and ListString classes with no ancestors.
As always, let me know what you think. driss @ zouak . com
PS: Extending
Want your own static Save method in StudentPersistanceManager or need to change something? For example:
public static new void Save(Student sampleStudent) {
// Trivial but effective
return ;
}
As you would expect, if you don't add the New or you add any additional Save method, you will get a warning that you are hiding the Save method from the PersistanceManager. However, part of the point is to standardize your approach so use this with caution.
This week I received my Motorola Q phone; Telus Mobility is my provider. The first thing, as any developer would, is I wanted to get my favoriate apps installed, and then get myself setup to write my .NET Compact framework apps and getting them on my Q. Btw, I love this device to pieces. It's awesome, and the people at Telus are awesome when you call for support. I hope that the Verizon below are like this, because this article is relevant to you too :)
First thing to note, in case it's not obvious to you, is that the Q is a Windows Mobile 5 SmartPhone, not a PocketPC. To some this is obvious by the nature of the device but if you tried to determine this by looking at the operating system details in the device, no dice. Me, I like to be certain, but no where does it tell you so I figured it out through examination of application behavior.
Being Able to Install Applications
When I tried to install my Audible.com player for audio books, a perfectly legitimate piece of software for digital audio books, I got an error telling me that the installation failed and that I didn't have sufficient security permissions. Security permissions? On my own device? Whaaaa?? A bit of Googling revealed that because this is a SmartPhone, and not a PocketPC, the device can be application locked by the carrier.
Next stop was this blog entry by Stuart Preston which was great for UK folks, but when I ran the RegEdit tool on my Q, it failed to allow me to change the values in the registry. I then decided to do something that I figured, under normal circumstances should not work (given what I've experienced in the past with technical support people) I decided to call Telus, my new provider. One legitimate “Would you mind if I transfer you, I have someone who is better capable of addressing this for you?“ later, and 4 minutes on hold after explaining my issue, I was told that really I should be calling Motorola and they would gladly help me but since they the guy was able to find the answer on hand, he would forward me an email with 2 files. Note to folks, the right thing to do here is call Motorola for Q support (In Canada at least, it's 1-800-657-7576). You'll get emailed SecPolicies.CAB file which will allow you to install what you want, and you can receive another item (which as a developer is much needed and appreciated) VZW_SpAddCert.exe. This allows you to add whatever certificate you want to your device in order to allow you to install any legitimate applications. The Windows Mobile development kit comes with some certificates for you to use and sign your applications with.
Getting Ready for coding
I started here at MSDN which houses all of the Windows Mobile materials. If you don't have it already, and if you're like me with a VS.NET 2005 installation you don't, get the .NET Compact Framework SP1 installed on your device. After that, you'll want to go to the Downloads section to get the SDK for SmartPhones (short cut here). Once that puppy's installed, then it's all from VS.NET 2005. I'll try to post an article soon with some tips and samples for .NET SmartPhone applications.
Tuesday, June 20, 2006
Level - Beginner to Intermediate
Audience - .NET WinForm Developers
The article doesn't get into multithreading itself, I'll leave that for another potential article, it focuses only on the proper way to make your WinForm work properly with multi-threading.
Recently I couldn’t remember how to make a WinForm have a responsive user interface that was updated by multiple threads under the covers. It’d been a while, and in my search, I quickly found the code I needed but I realized that there’s a reason why I regularly get questions about how to do this, about how to use threads, etc. it's because all the articles that I kept finding were all at the basic level, it didn't really show someone where you can go from there. It inspired me, and given that I was starting a technical blog, I thought it would be a good place to start.
For the person like myself who is looking for the quick answer, here it is:
// This is your event handler for some other event that the WinForm subscribes to.
void SomeEventHandler(MyArgs args)
{
// This gets invoked by the caller's thread, and not the Winform's, therefore
// it is not appropriate to update the WinForm here.
// Create an event handler Delegate
UIUpdaterDelegate updateUI = new UIUpdaterDelegate(UpdateUI);
// Now ‘schedule’ the update for when the Winform (i.e. this) is able to by calling
// the Winform's Invoke method.
this.Invoke(updateUI, new object[] { args });
}
// Here's the Delegate which uses an arbitrary parameter I created which allows me to
// pass whatever information I need. Note that there really isn't any point to being non-void
// because no one else is calling this. I can put as many parameters as I want, just include them
// in the object array above in (see the this.Invoke ... code)
delegate void UIUpdaterDelegate(MyArgs args);
// Here is the “Real“ Event handler for the event that the Winform subscribed to with the
// SomeEventHandler. It shouldn't be visible to anyone else, i.e. it's protected or use private.
protected void UpdateWithUIThread(MyArgs args) {
// Do the actual updating here
}
So now that the people who were looking for the quick answer are satisfied, let’s break this down. First off, why do this? And then why not just use the Background Worker thread?
Why?
While tweaking your applications business logic and your stored procedures is great and necessary in improving the performance of an application, you can only go so far and still likely end up with dissatisfied users. Often developers aren't sure what to do next and end up either trying to sell the user to “live with it”, or try some very significant refactoring of the application which tends to be lots of hours for little benefit, or end up recommending to improve the hardware. This also isn't a sufficient answer.
Very often the answer to the user's woes is incorporating multi-threading into the user interface, but that's not a trivial thing to do, particularly when you look at the documentation that's available. Returning control to the user to allow them to continue working, even if it is only on a limited amount of things while the background process is working, can make a world of difference. By the way you don't need to do this for every form, just the ones where you need it.
Also I should note that this approach also allows you to have your form subscribed for “interruption type events”, i.e. IF something happens let my WinForm know so that I can tell the user. An example of this could be a type of messenger application built into your app that informs the user “The customer record you are working on has just been checked out by Betty Simons” or “There is a new version of this application now available, would you like to get the update now?” There are many examples of where and when you might want or need to have your WinForm watch for something and need to get updated by another thread that's doing the actual watching.
Why Not The Background Worker
In .NET 2.0 (VS.NET 2005) there's a component called the Background Worker. At first I tried using this but I learned that it is very much geared to incremental, countable progress, fine for updating progress bars but not good enough as a general 'working directly with threads' replacement. Also, I found that it behaved a lot less predictably for my asynchronous UI updates than using threads directly, which was unacceptable for me and my clients. If it works great for you, please share with me where and how you use it as I haven't really seen any concrete areas of value of this control given the limitations that I ran into.
The Winform Thread
Updating the WinForm looks relatively straight forward, particularly when you aren't dealing with threads, but there's something going on that most of us aren't aware of at first, that when we step into Threading, trips us up badly. There's a thread that runs in our applications that is created by .NET automatically that is responsible for managing the interaction with the user and updating the form to reflect what they are doing. If they drag it, if they click on a drop down list, if they maximize it, it is that thread that makes sure the work gets done. When the user clicks on a button, it is that thread that runs the code for that button click method and it is this reason why the user can't do anything until that button click method finishes, because there's no thread to deal with what they are trying to do. It's like asking someone at the fast food 'counter interface' to get you a sandwich and wondering why the 'counter interface' isn't responsive while they are off getting you the sandwich, it's simply because there's isn't anyone there.
You'd consider the interface to be much more responsive if the 'counter interface' took your sandwich request, handed it over to someone else to go, and then asked you if you'd like anything else. Possibly as you continued your order, or afterwards when you were waiting, your sandwich would arrive. You'd have the feeling that it was quite because you just finished ordering your drink or fries and then 'bang' here is your sandwich and a moment later, the rest of your order.
When we first get into threading, and not realizing that forms are not designed to be updated only by the UI thread, we figure that we'll create a method on the WinForm that looks like this:
// Anyone can call this to update my UI and it won't affect the user responsiveness!!
public void UpdateProgressInfo (MyArgs args) {
statusLabel.Text = “Received Updated information at “+ DateTime.Now.ToString();
progressBar.Value += 1;
}
The problem with this is that it yields unpredictable results, and they drive you crazy trying to debug them because it “just happened once, no there it is again. Why the heck does it say “Received Upeleted record?” The problem arises because the user will do something that updates the user interface somehow and the UI Thread clashes with the thread that is calling your UpdateProgressInfo method, and a mess is created because the controls aren't thread safe. Even if you put a lock statement around it, it's still the wrong way to do things and can yield unexpected results.
Invoke the Winform
WinForm's have a method called Invoke which is your way of telling the form “Hey, when you have a sec, call this method with these parameters.” It literally looks like this:
this.Invoke(updateUI, new object[] { args });
You can pass whatever, and however many, parameters that you want, so args, args2, args3 of whatever types. Of course, the question is, when do I call this? In any event handler that your WinForm where it is handling the event that is on a threaded object. For example, say you have a TransactionProcessing object (transProcessingDaemon) that runs on its own thread or set of threads. Either in your WinForm's Init or Load there's a...
transProcessingDaemon.ProcessingDoneEvent += new MyTransProcessingEventDelegate(this.FakeUIUpdater)
Of course, your updateUI method needs to be in accordance with the MyTransProcessingEventDelegate definition, i.e. matching return type and matching parameter list.
The FakeUIUpdater, a bad name but there to illustrate the point, looks like this:
// This is your event handler for some other event that the WinForm subscribes to.
void FakeUIUpdater(MyArgs args)
{
// This gets invoked by the caller's thread, and not the Winform's, therefore
// it is not appropriate to update the WinForm here.
// Create an event handler Delegate
UIUpdaterDelegate updateUI = new UIUpdaterDelegate(UpdateUI);
// Now ‘schedule’ the update for when the Winform (i.e. this) is able to by calling
// the Winform's Invoke method.
this.Invoke(updateUI, new object[] { args });
}
The UIUpdaterDelegate referred above, is here
// Here's the Delegate which uses an arbitrary parameter I created which allows me to
// pass whatever information I need from the FakeUIUpdater to the real one. Note that there really
// isn't any point to being non-void because no one else is calling this. I can put as many
// parameters as I want, just include them in the object array above in (see the this.Invoke ... code)
delegate void UIUpdaterDelegate(MyArgs args);
The UpdateUI method looks like this:
protected void UpdateUI(MyArgs args) {
// Do the actual updating here
statusLabel.Text = “Received Updated information at “+ DateTime.Now.ToString();
progressBar.Value += 1;
}
I always make these methods protected or private, as no one else should be calling this method but of course.
This method will be called, i.e. invoked, by the UI Thread which means there will be no issues in terms of controls getting updated properly. So now when the ProcessingDoneEvent is raised, the WinForm's FakeUIUpdater method will be called which in turn 'schedules' the calling of the real method by the UI Thread.
So there you have it. At the end of the day, it's all about one method, the WinForm's Invoke, and about defining your delegates.
Have any feedback, thoughts, comments, ideas to improve this article? Drop me a line driss @ zouak.com
Thursday, June 15, 2006
My career with .NET started with Beta 1 when I was at Microsoft in their consulting division, after over 4 years I decided to head out on my own (www.zouak.com). Over the years I've authored articles and courses, I've taught courses, I've spoken at conferences (member of the MSDN Canada Speaker's Bureau), I've delivered many projects, and most importantly I've helped a lot of people get on the right path with .NET. So why a blog now?
In reading blogs and articles for a couple of years, I always felt there were gaps. These gaps were sometimes explaining technical concepts the way some customers or friends of mine need it explained, other times its topics themselves, and sometimes its higher level online discussions that are missing that talk about architectural or project lessons learned. This is what this blog will be focused on. Sometimes it will be about code, sometimes solution concepts, sometimes technical commentary. At the end of the day, it's about giving you some ideas and providing me with an opportunity to get feedback from you the reader regarding any ideas I put forward and what your experiences are like.