I like Windows Presentation Foundation (WPF) very much, especially its implementation of the Model-View-Controller (MVC) design pattern. I've also grown to appreciate XAML as a declarative (if quirky) way of building complex user interfaces that integrate with a testable code file. However, every once in a while, I end up with a WPF Window that takes a long time to render, or renders in a bizarre series of jumps. If that's happened to you, it's worthwhile to download Microsoft's WPF Performance Suite.
The suite includes two tools: Perforator and Visual Profiler. Neither will tell you what to do to fix your problem, but both will help you locate the problem.
Perforator concentrates on the low-level routines that render your XAML. The download page for the package includes some useful information about the kind of values you should see with Perforator to help you figure out where your problem is. You can also experiment with various settings to see which (if any) will help with your problem.
While Perforator looks at how WPF is rendering your XAML, Visual Profiler shows how individual controls you've included in your XAML (Buttons, Lines and so on) are being rendered. In many ways, this is more useful to the developer: once you know what your problem controls are, you can focus on what's causing them to behave badly. The best solution may be to just do without them.
Posted by Peter Vogel on 01/13/20140 comments
The ability to nest one class inside provides a powerful way to encapsulate code inside a class to organize complex functionality used within a single class. A nested class looks like this:
Public Class MyClass
…code for the class…
Class MyNestedClass
End Class
Public Sub SomeMethod()
Dim mnc As MyNestedClass
mnc = New MyNestedClass()
…using the nested class…
End Sub
End Class
As the example shows, in the surrounding host class you can instantiate the nested class and use it. No other class, however, can access the nested class. Nested classes give you a way of organizing the functionality of the host class without exposing that functionality to other classes (or cluttering up your IntelliSense lists with new classes that are only useful in one place -- the host class).
For instance, in a recent application, I needed to manage the permissions and privileges for three levels of users in a form. I created a class for each type of user, with each class holding all (and only) the code for managing what that type of user was allowed to do. Any permissions-related code that was shared by all the users I put in a base class that the three user classes inherited from, giving me four classes altogether. This design cleaned up and organized my permissions code while simplifying the code in the host that set permissions in the form's user interface: the host class just instantiated the right nested class and called its permissions-related members.
Since these classes were only relevant to that single form, I nested all four classes within the controller for that form. With that design, code in the form could instantiate the nested classes and use their members, but the classes didn't appear in any IntelliSense lists outside of the host class.
If you do need to make a nested class available to the outside world, you can add a property to your host class that returns the nested class (as I did in a recent column on creating a fluent interface).
And, of course, you can argue that any class that needs nested classes is too big and too complicated, and is probably violating the Single Responsibility Principle. But that's a different discussion.
Posted by Peter Vogel on 01/09/20140 comments
If you miss the free version of Reflector now that Red Gate's taken it over, and if you don't appreciate the functionality that Red Gate has added to it, then ILSpy is for you.
ILSpy will decompile any .NET DLL back to either Visual Basic or C# (your choice), and provide a viewer that lets you browse the results. If you want to find out how the code behind the framework DLLs works (or if you've just lost your source code), ILSpy will let you see it. There are even a few plugins for ILSpy that enhance the basic package (and they're also free).
ILSpy doesn't provide the tight integration with Visual Studio (and Visual Studio debugging) that Red Gate's Reflector does, but -- did I mention this? -- it won't cost you a dime.
Posted by Peter Vogel on 01/08/20140 comments
Over a series of articles about commenting, I discussed why the key issue is to write ROC (Really Obvious Code). If you do, then the only comments you need to provide for your methods should be what parameters the method expects, what your method will do with those parameters, what the method will return, and any side effects of executing the method (e.g., database updates). If you bought into that plan (and some readers did not), then the best place to put that documentation is where Visual Studio will make the best use of it: in IntelliSense, by using XML comments.
To create the structure for your XML comments, click your mouse before your method declaration; then, in Visual Basic, type three apostrophes ('''); in C#, type three forward slashes (///). In either case, Visual Studio will add a framework to hold the comments for your method, for each of the parameters the method accepts, and for your method's return value (if any). All you have to do is type in your content.
Not only will the programmers who work on your code find all the information they need when changing your code, the developers who use your methods will find that IntelliSense delivers your documentation to them when they use your methods.
Posted by Peter Vogel on 01/07/20140 comments
You're working with a variable, property, method or class and you need more information about it. If you hover your mouse over the item's name, IntelliSense displays the information for you. But when you need more information or, especially, if you want to make some changes to the item, clicking on the item's name and pressing F12 will take you to it.
When you're done making your changes, you probably want to go back to that original code. Pressing Control_- (<Ctrl> minus) will take you there (officially known as navigate backward or BrowsePrevious). If Control_- doesn't take you back to where you want to go immediately, it's only because it will stop at some other places where you rested between when you pressed F12 and where you are now. Just keep pressing Control_- and you'll eventually get back to where you want to be.
Posted by Peter Vogel on 12/09/20130 comments
Like everyone else, I like code-first Entity Framework (EF) development because it makes it so easy to integrate custom code with my EF entity code. But even in a pure code-first development, I suspect that most developers don't generate their databases from their entities because, most of the time, the database already exists (and, besides, the DBA won't let developers anywhere near the database's schema). That means you have to write all the repetitious property declaration in the entity objects to mimic the tables you'll be working with. Wouldn't it be nice if you had a tool to do it for you?
There are POCO generators out there, but you already have a tool: the ADO.NET Entity Framework database-first designer. The original versions of the designer generated a lot of peculiar code. More recent versions generate code that looks very much like the code you should write when doing code-first development. Why not take advantage of that?
Start by adding a new project to your solution. Then, to get the cleanest entity code possible, use NuGet to add Entity Framework 6.0 to the project. From Project | Add New Item, add the ADO.NET Entity Data Model and use the Wizard to work through adding the tables needed for your project. When you're done, close the designer to ensure that all the code for your entities is generated.
Now drill down beneath your edmx file in Solution Explorer to find your code files. You can skip the file called <NameOfYourModel>.cs/vb and <NameOfYourModel>.Designer.cs/vb (though, since the files have nothing in them, there's probably no harm in including them). Once you've found the files, still in Solution Explorer, drag them to your "real" data access project. Whenever you need to add another table you can return to the project with the designer and use it to generate your code for you.
This isn't a perfect solution: The edmx generator in EF 6.0 doesn't add any data annotations to the entities it generates, for instance (recently, I needed to add the Key attribute to the primary key properties on a project). This solution is also easier to implement in Visual Basic than in C# because of the embedded namespaces in the C# files. Even in C#, though, a project-wide search-and-replace will fix that problem. But by using a tool from the EF team to generate your EF code, you're guaranteed to be getting the best (and most up-to-date) EF code possible.
Posted by Peter Vogel on 12/04/20130 comments
I've been working on a Windows Forms application for one of my clients and, in the application, I use the CheckedBoxList and the DataGridView. Both of them have really useful collections: the CheckedBoxList has a CheckedItems collection that holds all the items that the user has checked, and the DataGridView has a SelectedRows collection that holds all the rows the user's selected, for instance. The CheckedItems collection can hold any object I want while the SelectedRows collection holds DataGridViewRow objects.
The problem is that neither of these collections will work with LINQ.
Fortunately, rather than use For…Each loops, I can use the OfType method to convert these collections into something that will work with LINQ. All I have to do is pass the OfType method the object type held in the collection. For instance, to use LINQ with the DataGridView's SelectedRows collection, I use this code; it converts the DataItem property for each row into the object associated with each row:
Dim coll = From rw In Me.gvInvoices.SelectedRows.OfType(Of DataGridViewRow)()
Select CType(rw.DataBoundItem, ClaimCededDetailClass
The following code processes the ClaimHeaderClass objects I hold in my CheckedBoxList, and hands back those object that have their AuthorizationLevel property set to "High":
Dim cc = cblClaims.CheckedItems.OfType(Of ClaimHeaderClass).
Where(Function(chc) chc.AuthorizationLevel = "High")
But wait, there's more! I have a Panel on the form with a set of RadioButtons in it. The Panel, of course, has a Controls collection that holds all of those RadioButtons. This code converts that collection into a LINQ-compatible collection of RadioButtons, then lets me find the name of the RadioButton the user selected:
strRadio = (From rb In Me.plStatusRadio.Controls.OfType(Of RadioButton)()
Where rb.Checked
Select rb.Name).FirstOrDefault
Posted by Peter Vogel on 11/15/20130 comments
About a year ago, Patrick Steele did a great job of describing AutoMapper: an absolutely necessary tool if you're using Data Transfer Objects to move data between parts of your application. AutoMapper will automatically move data from your business entities into the corresponding properties on your DTO, saving you many, many lines of repetitious assignment statements. It also means that if you add a new property to your DTO, AutoMapper will automatically pick up the corresponding property from the entity; no further changes to your code required.
You do need to be careful, however, when moving your data from a DTO and into an Entity Framework (EF) entity object. By default, AutoMapper creates a new instance of the object that the data is being moved into. If you write code like the following, for instance, the Customer object in custExisting that's returned from AutoMapper is a different object from the Customer object retrieved from the DbContext (even though the custExisting variable points to both of those objects):
Mapper.CreateMap(Of CustomerDTO, Customer)()
custExisting = dbs.Customers.Single(Function(c) c.Id = custDTO.Id)
custExisting = Mapper.Map(Of CustomerDTO, Customer)(custDTO)
That's bad, because EF won't track the changes made to that new custExisting object: When you call SaveChanges, nothing will be saved back to the database. This is a common-enough problem that there's even some misinformation about it floating around. I've seen a couple of forums, for instance, where people with this problem have been told that AutoMapper can't be used to update entities.
You can update entities with AutoMapper. Here's how: pass both the DTO and the entity object to AutoMapper's Map method. That's what this code does:
custExisting = Mapper.Map(Of CustomerDTO, Customer)(custDTO, custExisting)
Rather than creating a new entity object to return from the Map method, AutoMapper now updates the entity object passed in the second parameter and returns it to my custExisting variable. As a result, EF will track the changes made to the entity object; and, when you call SaveChanges, your updates will be sent to the database.
Posted by Peter Vogel on 11/06/20130 comments
I'm sure that by now, mentioning these three tools is almost redundant, but even if you're working on a single computer on your own, Subversion lets you have as much (or as little) source control as you want. Subversion is ridiculously easy to install and start running.
After installing Subversion on the computer that holds your repository, add TortoiseSVN to give you source control from Windows Explorer on whatever computer(s) you have files you care about. To connect the two, copy the URL for your Subversion installation (it's available from a context menu) and paste it into the dialog box that pops up when you start TortoiseSVN. To integrate with Visual Studio, shut down Visual Studio and install VisualSVN. When you start Visual Studio backup, go to your new VisualSVN menu to connect your project to your repository.
It's all free and takes only a few minutes to download, install, and start saving your work to a central repository that will manage your code and its versions.
That's just the simplest installation. If you don't like VisualSVN, there are several other tools for integrating with Visual Studio. Several of my friends speak highly of AnkhSVN, for instance, which is always free, while VisualSVN is only free under some scenarios.
I work on a single laptop with multiple virtual machines (typically one VM for each client/project). I have the Subversion server running on my host machine, and connect to it from each of my VMs, with a separate Subversion repository for each VM. When I switched over to Subversion I probably spent as much time adding the repository to my laptop's backup plans as I did installing the three packages.
Posted by Peter Vogel on 10/30/20130 comments
This isn't so much a tip as a clarification: I often find that people are confused about what happens when you press F5 vs. when you press Control_F5. Here's the best description I've found (and it's from the blog where I've found most of the Visual Studio tips that I talk about here).
However, the blog's claim that there isn't much difference between F5 and Control_F5 isn't quite true; there are a number of differences I keep stumbling upon. I suspect that, from a technical/internals point of view, the statement that there aren't many differences is true. But for a developer using Visual Studio, there are a number of "operational" differences.
For instance, if you want to test your user interface's error handling, use Control_F5. With plain old F5, Visual Studio stops on the line that throws the exception; with Control_F5, Visual Studio lets your Try…Catch blocks handle the exception.
Here's another one: If you run a Console application with plain old F5, the console window flashes on the screen and disappears, unless you add a Console.ReadLine to your code; with Control_F5, the console window is held on the screen until you hit the Return key.
I bet that's not all of the differences. What ones do you know about?
Posted by Peter Vogel on 10/22/20130 comments
I know that Windows Forms are considered old fashioned, but I've got clients with applications that still use them. As I noted in my previous tip, I recently had to support letting the user sort by any column in a grid. If I was going to do that, I felt I should let the user know what column and direction they'd just sorted the grid in. The DataGridView lets you do that through the column's SortGlyphDirection property: just set the property to one of SortOrder.Ascending (little arrow in the column header pointing up), SortOrder.Descending (little arrow pointing down), or SortOrder.None (no arrow in the header).
When the user clicks on a column the first time, I sort the column in ascending order; with a second click on the column, I reverse the order. If the user changes columns, I erase the glyph in the previous column. To keep track of the necessary information, I declare two variables outside of any method: The Headers collection keeps track of what direction each column is sorted in, and the OldColumn variable keeps track of the last column sorted:
Private Headers As New Dictionary(Of String, SortOrder)
Private OldColumn As DataGridViewColumn
I put the actual sort code in the DataGridView's ColumnHeaderMouseClick event, whose parameter includes the column position the user's clicked on (the ColumnIndex property). I use that parameter to get a reference to the column the user's selected:
Private Sub CustomersView_ColumnHeaderMouseClick(…
Dim col As DataGridViewColumn
col = Me.CustomersView.Columns(e.ColumnIndex)
In the event handler, I check to see if there's a setting for the current column in the Headers collection. If there isn't, I just sort in ascending order; if there is, I use that value to decide what order to sort the column in:
If Headers.ContainsKey(e.ColumnIndex) = False OrElse
Headers(e.ColumnIndex) = SortOrder.Descending Then
Headers(e.ColumnIndex) = SortOrder.Ascending
Customers = Customers.OrderBy(
Function(c) prop.GetValue(c, Nothing)).ToList
Else
Headers(e.ColumnIndex) = SortOrderDescending
filteredInvoices = filteredInvoices.OrderByDescending(
Function(c) prop.GetValue(c, Nothing)).ToList
End If
After I finish sorting, I refresh my grid's DataSource with the new collection, clear the sorting glyph in the previous column, set the glyph in the column I'd just sorted, and keep track of which column I've just sorted for next time:
CustomersView.DataSource = Customers
If OldColumn IsNot Nothing Then
OldColumn.HeaderCell.SortGlyphDirection = Windows.Forms.SortOrder.None
End If
col.HeaderCell.SortGlyphDirection = Headers(e.ColumnIndex)
OldColumn = col
Now, by glancing at the grid's column headers, the user knows which column was sorted last, and in what order.
Posted by Peter Vogel on 10/17/20130 comments
In the bad old days (before LINQ), I used to concatenate together SQL statements. That left me open to SQL injection attacks, of course, but it was so convenient: I could dynamically put together whatever SQL I needed at runtime. With LINQ, however, not so much (though I understand that there is a version of Dynamic LINQ out there). Even with ordinary LINQ, though, you can select which properties in an object you want to use at runtime; at least when you're sorting (and, probably, elsewhere but I haven't tried it yet).
Recently, I needed to support a grid for a client who wanted to be able to sort on any column. I was setting the grid's DataSource to a collection of objects. While this simplified getting the objects displayed, it also turned off the grid's automatic sorting capability. To get around that, I added some code to the grid's ColumnHeaderMouseClick event to sort the grid. What I didn't want to do was write a separate method to sort on each grid column (especially because this client kept changing his/hers/its mind about what columns should or shouldn't be in the grid).
Fortunately, each grid column held the name of the property that the column was responsible for displaying from the objects in the grid's DataSource. Given a property's name, I retrieved the PropertyInfo for that property and used its GetValue method in my LINQ code.
First, I retrieve a sample object from the collection of objects (Customers, in this case):
Dim cust As Customer
cust = Customers.First
Then I retrieve the PropertyInfo object for the property whose name is in the PropertyName string variable:
Dim prop As PropertyInfo
prop = cust.GetType.GetProperties.First(
Function(pr) pr.Name = propertyName)
Now I use the PropertyInfo object's GetValue method in my LINQ statement to sort my list:
Customers = Customers.OrderBy(
Function(c) prop.GetValue(c, Nothing)).ToList
I'm looking forward to finding out how many places I can use this technique.
Posted by Peter Vogel on 10/07/20130 comments