Tuesday, June 22, 2010

How to center a check box column in the WPF DataGrid

A common problem with the DataGridCheckBoxColumn of the WPF DataGrid is that the CheckBox is not centered in the cell which is especially ugly in rows that are higher than the CheckBox itself.
Due to the nature of how a column in the DataGrid is generated it isn't very easy to use a simple style or ones own template column.

But there is a much shorter and better way, we can simply extend the DataGridCheckBoxColumn to provide our own, centered, CheckBox.

public class CenteredCheckBoxColumn 
           : DataGridCheckBoxColumn 
{
  protected override FrameworkElement 
    GenerateEditingElement(
      DataGridCell cell, object dataItem) 
  {
    var checkBox = 
      base.GenerateEditingElement(cell, dataItem);
    checkBox.HorizontalAlignment = 
      HorizontalAlignment.Center;
    checkBox.VerticalAlignment = 
      VerticalAlignment.Center;
    return checkBox;
  }

  protected override FrameworkElement GenerateElement(
      DataGridCell cell, object dataItem) 
  {
    var checkBox = 
      base.GenerateElement(cell, dataItem);
    checkBox.HorizontalAlignment = 
      HorizontalAlignment.Center;
    checkBox.VerticalAlignment = 
      VerticalAlignment.Center;
    return checkBox;
  }
}

We can now use our CenteredCheckBoxColumn in the same way we use the standard columns.

Submit this story to DotNetKicks

Tuesday, May 25, 2010

A case for a nameof() operator

Refactoring your code has come a long way, especially with tools like Resharper one seldom worries about changing namespaces, renaming classes or extracting methods.
But one major breaking point still exists: Using property names as strings. And C# contains two very popular interfaces in need of property name strings.
INotifyPropertyChanged:
public string Name {
  get { return name; }
  set {
   name = value;
   InvokePropertyChanged("Name");
  }
 }

and WPFs dependency properties:
public static readonly DependencyProperty 
  ViewModelProperty = 
    DependencyProperty.Register("ViewModel",
                                typeof(MyViewModel),
                                typeof(UserView));

Both interfaces, especially with the rise of WPF/Silverlight applications, are used quite a lot. And it is not only the newbie programmer who will inadvertently break some code because he forgot to change the string when renaming a property. And while WPFs dependency properties will at least throw an exception in most cases bugs will slip in for the property changes or other interfaces which rely on the correct strings.
Since the beginning of C# people searched for solutions which do not break on refactoring, and at least since LINQ there is a viable workaround as LINQ queries have the unique property of containing string representations on their member expression parts:
public string ParsePropertyName<T>
(Expression<Func<T>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
...
public string Name {
  get { return name; }
  set {
   name = value;
   InvokePropertyChanged(
     ParsePropertyName(()=>this.Name);
  }
 }
While this simple solution has drawbacks (e.g. when no instance of a class is available) it seems to be used quite often as its described and discussed quite a lot. E.g. here here here here or here.

Even though the solution remains what it is: a hacky workaround.
And that is why I would propose adding a simple nameof() operator instead. It would allow us to get rid of all the fluff we add to get the name of a property and would let us write this code instead:
Code:
public string Name {
  get { return name; }
  set {
   name = value;
   InvokePropertyChanged(nameof(Name));
  }
 }

The compiled code would still look the same, without the performance drawbacks of LINQ queries, and it wouldn't break on refactoring. As an added bonus we get the functionality on methods, events... you name it.
I rest my case, what does the jury think?

Submit this story to DotNetKicks

Thursday, May 20, 2010

Committing bound cell changes immediately in WPF Datagrid

The WPF DataGrids default mode of operation is committing all changes on a per-row edit instead of a per-cell edit. In this post we will see how to change that behavior to do a per-cell commit regardless of the bound object's capabilities.

But first a little bit about the workings of the DataGrid.
When binding data in a WPF DataGrid it holds all changes to the data in an intermediary object. If the user edits a cell the changes will be done only in this intermediary object, the exception being if the bound object does implement IEditableObject in which case the DataGrid uses the object's edit capabilities instead.
But if we do not have an IEditableObject to bind to all changes made inside the row will only be committed to the bound object once the row edit ends. If we still need to commit on a cell by cell basis we need to attach a handler to the CellEditEnding event of the grid and use the following code in the handler.

private bool isManualEditCommit;
private void HandleMainDataGridCellEditEnding(
  object sender, DataGridCellEditEndingEventArgs e) 
{
 if (!isManualEditCommit) 
 {
  isManualEditCommit = true;
  DataGrid grid = (DataGrid)sender;
  grid.CommitEdit(DataGridEditingUnit.Row, true);
  isManualEditCommit = false;
 }
}

This will update the bound object whenever a cell edit is ending, i.e. whenever the cell looses focus.

Submit this story to DotNetKicks

Monday, August 3, 2009

The woes of file extensions in the SaveFileDialog

I stumbled upon a rather annoying problem in the SaveFileDialog (System.Win32) in one of my WPF applications. The application allows saving of its own type of project file with a custom extension ".mypi" and of course loading those files again.

The code for saving:
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "MY Project|*.mypi";

and for loading

OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "MY Projects|*.mypi";

Now some users were complaining about "lost files" that they "could not open", and after a bit of digging around I found that they entered file names in the form of "Project.2009.07.07" in the SaveFileDialog. Now what I would have expected is that the dialog would append the only available extension "mypi", but as the documentation correctly states for the "AddExtension" property (which is set to "true" by default):
Gets or sets a value indicating whether a file dialog automatically adds an extension to a file name if the user omits an extension.

Now the important part is "if the user omits an extension", and since .07 is a valid extension the dialog will not add anything to "Project.2009.07.07". And thus when trying to open the file again the filter will not pick up on it.

The preferred workaround is to change the file name after the dialog closes, note though that you have to hook the SaveFileDialog.FileOk event to check if the file with the added extension exists, otherwise this check will not work correctly in the file dialog.

Not being able to force the SaveFileDialog to add an extension to every file name entered by the user is a rather poor design decision, as the user will assume that a save dialog which only allows to save a certain kind of file will generate such a file. He is strengthened in that assumption by other applications like Word, MS Paint, etc..., which do not display that behavior but always append the filter extension to the file name.
Thus for every SaveFileDialog the same workaround has to be used and functionality that already is in the SaveFileDialog has to be duplicated (check if file exists, check if filename is too long, etc...) and the appropriate error messages localized.

In conclusion the SaveFileDialog should be extended in future versions to allow that kind of behavior without any workaround.

Does anyone know of an alternative route to solve that problem or a third party save file dialog (maybe even written in proper XAML for styling and extendibility)?

Submit this story to DotNetKicks

Tuesday, January 15, 2008

Tip of the Week - The Right Mindset

This week's tip is for all coders out there who want to grasp the bigger picture and go beyond the code and develop the right mindset for a good software developer. Karl Seguin condensed years of experience, common sense and sharp observation of what matters in software development into a 7 part overview. Start with the first part or grab the whole tutorial as a PDF to read on dead trees and become a better, more productive developer. While focusing on .net development this is a must read for everyone.

Submit this story to DotNetKicks

Monday, December 17, 2007

Tip of the Week - Multicoring

Never has programming for multiple cores been easier as with the Task Parallel Library (TPL) for .NET. Make sure to check out this simple introduction to see the power and ease of use the TPL brings to make your code ready for multi core support.

Submit this story to DotNetKicks

Monday, December 10, 2007

Tip of the Week - Visual WPF Debugging

This weeks tip goes out to all the WPF developers out there:
Mole II is a graphical debugger for WPF and once used you won't know how you could ever live without it. A must have tool for the tool belt of every serious WPFer.

Submit this story to DotNetKicks