Wednesday, October 19, 2011

Markup Extensions in Silverlight have to be public

In the good-to-know category we today have a problem out of the Silverlight 5 world, where Markup Extensions are now possible. Beware though: If the class is not public Silverlight will simply freeze while starting without giving a proper error message. So always be sure to make your extensions public.

Good to know and would have saved me quite some time if I knew that beforehand.

Submit this story to DotNetKicks

Monday, August 8, 2011

Authentication Suffix in SharePoint hosted Data Service

When hosting a Data Service inside SharePoint using the MultipleBaseAddressDataServiceHostFactory you might notice that your service endpoints get redirected depending on the authentication schema (as described here). The way it is supposed to work is that you do not notice any of the redirections on the user side.
But the way the default behaviour works is that also the service base will change accordingly. I.e. if you load the .svc for anonymous authentication the base attribute on the service will look like this:

<service 
xml:base="http://localhost/_vti_bin/test/odataservice.svc/anonymous/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">

(Notice the anonymous part in the base attribute.)

But any request to the service with the authentication suffix be it anonymous, basic etc... will be interpreted by your OData framework and thus you get the error message: Resource not found for segment 'basic' when navigating to http://localhost/_vti_bin/test/odataservice.svc/basic/Customers for example. This is because internally the url is .../basic/basic/Customer after the redirect according to the authentication schema.

Since some services actually rely on the correct base-url (e.g. PowerPivot) that is not the behaviour we would want to see.

The not so well documented fix for that behaviour is to set the ServiceFactoryUsingAuthSchemeInEndpointAddressAttribute on your service class like this:

[ServiceFactoryUsingAuthSchemeInEndpointAddress(UsingAuthSchemeInEndpointAddress = false)]

Afterwards you will have the much more sensible behaviour of a clean base-url in your .svc service description and no more confused clients which access your service through the authentication suffixes.

Submit this story to DotNetKicks

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