Visual Studio 2008 : Where is my Solution Explorer item sort gone ?

By Jerome at December 11, 2007 13:58 Tags: , ,

As a new user of VS2008 and senior user of VS2005, you may just just start to convert your projects to VS2008. Good. Then you look at your solution and start to look for your favorite project in the Solution Explorer and have trouble finding it... Of course ! The list is not sorted...

You may wonder, where is that sorting gone ? Well, I don't know exactly but it seems that if you select a project, press F2, then enter without modifying a thing... The tree sorts itself out! The bad thing is that you can't save that sorted list, as it seems that it is only the TreeView that sorts the item list, not the internal list that is sorted... I know for a fact that there are some PowerToys that sort the entries in the SLN file, I'll try to look for that.

How could something as visible as this has passed through the beta phase ? :)

The (non generic) System.Action delegate

By Jerome at December 09, 2007 22:33 Tags: , ,

There's been one delegate I wish would have been integrated in .NET 2.0 :

1:
2: namespace System
3: {
4:   public delegate void Action();
5: }

Well, it's been added to the .NET framework 3.5. That will avoid me to create here and there an empty delegate that returns nothing and takes nothing in parameter. It's particularly useful with anonymous methods.

My discovery of that particular type is a bit odd though. A big project I'm currently working on is defining this type :

1:
2: namespace T1 { public enum Action { A } }

"T1" is made up, "Action" is not. And it's being used like this :

1:
2: Action a = Action.A;

And it compiled just fine using .NET 2.0. During a migration to the .NET Framework 3.5, I came across some compilation problems telling me that the resolution of "Action" was ambiguous. I thought at first that this was because of a change in the resolutions of types in C# 3.0, but after a bit of digging I found out about that non-generic System.Action delegate, which is defined in System.Core.dll. By the way, they also added some other System.Action overloads with two, three and four generic parameters.

Reflector tells me that the non generic version is being used by System.Linq.Expressions.Expression. I'm guessing that might be used by LINQ in some way... maybe by some generated code.

Binding a C# property to a WPF validated Control

By Jerome at August 29, 2007 05:48 Tags: , ,

The DataBinding in WPF allows the binding of control properties to many things, like other control properties, arrays, data providers, ... But it can also bind a control property to a property defined by code on the C# side.

It is interesting to bind to C# property to be able to have the integrated WPF validation and still use a simple property from the code. In that case, I wanted to have the validation of a TextBox displaying a DateTime object.

Here's how to do this.

On the C# side :


public partial class Window1 : Window

  public Window1() 
  {   
    MyDate = DateTime.Now;
    InitializeComponent();
  }
  public DateTime MyDate { get; set; }
}
 

Note that I'm using the latest C# 3.0 syntax to declare variable-less properties. This is compiler trick, the variable is still declared at compile time, but since I don't need to have a specific code in the get or set accessor, it can stay in this short form.

Now on the XAML side :


<Window ... >

  <TextBox Width="100" Height="20">

    <Binding Path="MyDate" RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}" UpdateSourceTrigger="PropertyChanged">

      <Binding.ValidationRules>

        <ExceptionValidationRule />

      </Binding.ValidationRules>

    </Binding>

  </TextBox>

</Window>

The interesting part here is the use of RelativeSource and the FindAncestor mode. Here, we're looking for the property MyDate from the nearest ancestor instance of the Window type, from the current instance.

This way, you'll have a validated date time in your property value. Just make sure you're checking that the value is really valid using the System.Windows.Controls.Validation class.

Google, Sitemaps, Multi-Culture, and ASP.NET

By Jerome at July 26, 2007 13:48 Tags:

A while ago, by watching my web server logs and some statistics on Google Analytics, I discovered that writing content in english and having a server based in the US has the effect of my site being mostly visible from within the US. It is also a bit visible when using localized google sites, but the page rank is quite low... So I'm tried to improve my page rank.

Google Webmaster Tools is an interesting tool shows rather precisely how Google scans a website. It can alert if it encounters server errors (500), broken links (404) or any other unusual error for links that point to a website. That tool helped me fixing an URL rewriting bug a while ago.

There's also a section called Sitemap, which allows you to provide explicitly a list of urls from your site. This is more of a hint than an order, but that helps to have the content being indexed a bit more quickly.

To have my content displayed in multiple languages, namely English, French and Spanish, I tried multiple techniques, one being the use of the automatic culture selection of ASP.NET. This is fine when a "real" user is browsing a site, but for the indexing this is not effective. The automatic culture is based on the accept-language HTTP header, which is not set by the google crawler... Google then only indexes the default language, which is English for me.

Then I tried the HTTP query parameters, by adding a &lang=fr-FR at the end of each page. Well, that not good enough either, since it seems that Google is not indexing dynamic content pretty well.

Finally, I tried adding the culture just before the aspx extension (default.fr-FR.aspx), which "fools" google into thinking this is static content. This is an extension of the url rewriting technique I use to have my urls containing the titles of my blog posts.

This time it worked! I have my remote control page listed in the first page of Google France and Spain with "Bluetooth Remote Control" query. Also, to make sure that I have links to each and every language available without explicitly placing them in the sitemap, I also placed "language" flag image links at the top of each page. This is not useful for real users, since culture will probably be selected correctly in the first place, but it'll help indexing.

I also noted that having Hn HTML tags improves indexing. Search engine rank optimization is a strange and obscure science... :)

PS. : Sorry for the bad spanish language, it's a raw Google translator cut and paste. I'm in the process of having the text checked by a spanish speaker :)

"No files were found to look in. Find was stopped in progress." in VS2005

By Jerome at June 19, 2007 07:08 Tags: ,

There are bugs, mystical bugs I may add, that no one has been able to reproduce, nor find a fix for, well at least that do work on every occurrence. VS2005 has one of these, where when you try to use "find in files", you get a "No files were found to look in. Find was stopped in progress." and that's it. No disk access, no registry relevant access, no relevant file access.

Some have found that pressing Ctrl+Scroll Lock may help, well, it did not help for me. Some other tried the reboot, which seems to work better. You can also
spin around three times on your chair before doing that, that might also help.

Then I remembered that some times, because it seems that the CLR maintains some kind of "cross process state" (I don't know what it acutally is, so I'm just guessing) that cripples all the .NET processes that are running. The only way to reset that state is to kill all processes that are using the CLR.

That means killing every standard application, plus IIS's aspnet_wp, and if you have .NET 3.0, PresentationFontCache.exe, ...

That did the trick for me, after killing all these processes and running VS2005, my search was up and running :)

WCF, NuSOAP and ArrayOfString

By Jerome at April 16, 2007 15:21 Tags: , , , ,

When exposing a WebService via WCF, you might want to expose something like this :


[DataContract]
public class SomeContract
{
  [DataMember] 
  public string[] Values { get; set; }
}

For that particular data contract, WCF will be generating a WSDL with something like this :


<xs:complexType name="SomeContract">

  <xs:sequence>

    <xs:element minOccurs="0" name="Values" nillable="true"

                type="q1:ArrayOfstring"

                xmlns:q1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />

  </xs:sequence>

</xs:complexType>

With ArrayOfString being defined like this :


  <xs:schema elementFormDefault="qualified"

             targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"

             xmlns:xs="http://www.w3.org/2001/XMLSchema"

             xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">

    <xs:complexType name="ArrayOfstring">

      <xs:sequence>

        <xs:element minOccurs="0" maxOccurs="unbounded" name="string" nillable="true" type="xs:string"/>

      </xs:sequence>

    </xs:complexType>

    <xs:element name="ArrayOfstring" nillable="true" type="tns:ArrayOfstring"/>

  </xs:schema>

In general, that would be fine. The type "ArrayOfString" is defined in a different namespace, but this should not be a problem.

So, to use that particular type in a method call, you should have a document like this one :


<SomeContract>

  <Values xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">

    <a:string>My Value</a:string>

  </Values>

</SomeContract>

"string" elements are contained in a different namespace from the SomeContract element. However, the NuSOAP stock version 0.7.2 has a problem with that kind of schema, and generates instead something like this :


<SomeContract>

  <Values>

    <string>My Value</string>

  </Values>

</SomeContract>


When the WCF deserializer receives a document like this one, it does not find the "Values" member in the namespace he's looking and ends up creating a SomeContract instance with a null array of strings.

Since there's no way of fixing NuSOAP, you may need to tweak your contract to help NuSOAP serializing your data without a namespace.

The CollectionDataContract attribute seems to be the way to go, since there is a way to specify the namespace to use when generating the metadata. The service contract then looks like this :


  [DataContract(Namespace = "http://my.name.space")] 
  public class SomeContract 
  { 
    [DataMember] 
    public ArrayOfString InvalidIdentifiers { get; set; } 
  } 

  [CollectionDataContract(ItemName="string", Namespace="http://my.name.space")]
  public class ArrayOfString : List<string> { } 

Thereby placing everything in the "http://my.name.space" namespace.

You might need to tweak a bit the ArrayOfString class, especially if you need to assign it from an actual string[] instance, but you get the idea.

WCF WebService behind a NAT Gateway

By Jerome at April 15, 2007 11:06 Tags: , , ,

I'm currently working on a WCF service that's exposed via a basicHttpBinding, with some exposition of the metadata via a WSDL url.

The metadata generator has been improved a bit since it is now split into multiple files, with references from the first wsdl to other URI's. There's not much to do to have that WSDL generated, and the generator take the liberty of using the machine's name to create reference URIs.

Most of the time, this is a good idea, but sometimes when your machine is behind a NAT gateway doing some port forwarding, your machine probably won't have the public FQDN used to access your gateway. You then end up with a root document referencing URI's with a host name that is not valid on the other side of the gateway.

The solution to change that behavior is quite simple : Just change the host name IIS is listening on. Use the MMC snap-in, and specify that your port 80 (or whatever port you're using) is listening on your external FQDN. WCF will then use that host name when generating URI's. Also don't forget that if you specify a host name, you might need to add an other entry to be able to access your website using "localhost".

This operation is also needed for servers farm when doing some load balancing.

WPF DataBinding and Application Settings

By Jerome at February 15, 2007 21:47 Tags: ,

Well, yet an other post on WPF and some DataBinding. But this time, this is about DataBinding to application settings that are automatically generated by visual studio. These settings come in handy when you want to save your application settings per user, or have some application wide settings. In my case, I wanted to have my application to remember its size and position, as well as the window state.

WinForms were providing an UI to do this, and I wanted to have all that functionality back. It is not all that "visual" as WinForms can do it, but it works rather well. I guess that Orcas will provide a way to do this visually.

All I had to do to use these settings from XAML was to create a resource to be usable for DataBinding, from a separate file :


File: SettingsRes.xaml



<ResourceDictionary xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation

                    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 

                    xmlns:settings = "clr-namespace:WindowsApplication2.Properties">

  <ResourceDictionary.MergedDictionaries>

    <ResourceDictionary>

      <settings:Settings x:Key="settings" />

    </ResourceDictionary>

  </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

WindowsApplication2 is the default namespace for the application, and since the Settings class is automatically generated, the default namespace is used. This resource will be used application wide and is referenced like this :


<Application.Resources>

  <ResourceDictionary>

    <ResourceDictionary.MergedDictionaries>

      <ResourceDictionary Source = "SettingsRes.xaml"/>

    </ResourceDictionary.MergedDictionaries>

  </ResourceDictionary>

</Application.Resources>

This is handy because resources are separated in multiple files. I also add here references to value converters, when I have to use them everywhere in the application. Value converters, yet an other interesting subject. Maybe in an other post :)

Now, about binding the data. We want to bind the Width, Height and WindowState of the default Window to some settings in the ApplicationSettings.

Here's what to do :


<Window x:Class="WindowsApplication2.Window1"

        xmlns = http://schemas.microsoft.com/winfx/2006/xaml/presentation

        xmlns:x = http://schemas.microsoft.com/winfx/2006/xaml

        Height = "{Binding Source={StaticResource settings}, Path=Default.MainWidth, Mode=TwoWay}"

        Width = "{Binding Source={StaticResource settings}, Path=Default.MainHeight, Mode=TwoWay}"

        WindowState = "{Binding Source={StaticResource settings}, Path=Default.MainState, Mode=TwoWay}">

We create three bindings, each for an attribute, and set the source to the "settings" resource. The interesting part here is that the even thought the property we use is static, Settings.Default here, the Binding engine does seem to support it.

Setting the binding path to Default.MainWidth binds to the appropriate property. The last parameter instructs the binding to set the value of the property when the binding destination value changes, which can be the actual window height, for instance. The type of the property does not need to match the destination exact type, and since the type of the WindowState property is not known by VS2005 settings designer by default, setting the type to string seems to be enough.

Simple and easy. Now my application remembers where it was !

The sample here is a bit more complex, since it includes code to actually save the settings. But this is nothing really complex.

Man ! I like WPF... !

WPF DataContext and CurrentItem

By Jerome at February 13, 2007 15:23 Tags: , ,

DataBinding is one of the technologies I like the most. 

Winforms did a fine job introducing the concept, but it was pretty easy to be stuck when trying to perform complex databinding. .NET 2.0 brought the concept of BindingSource, which eased the management of multiple "Current items" on a single form. You might have encountered this when creating multiple master/detail views on the same form. That was the case when you wanted to walk through a set of tables through their relations, say down to three levels.

WPF has a far more advanced DataBinding engine and introduces the concept of DataContext. There's the notion of a hierarchy of DataContexts and a databound control uses the nearest DataContext available.

An example is better than a thousand words. Here's a data source :


<xmldataprovider x:key="ops" xpath="/data/level1">

  <x:XData>

    <data xmlns="">

      <level1 name="1">

        <level2 name="1-1">

          <level3 name="test">Some Value</level3>

          <level3>Yet an other value from level 3</level3>

        </level2>

        <level2 name="1-2">

          <level3>Some other Value</level3>

          <level3>Yet an other Value</level3>

        </level2>

      </level1>

      <level1 name="2">

        <level2 name="2-1">

          <level3>Some Value</level3>

          <level3>Yet an other value from level 3</level3>

        </level2>

        <level2 name="2-2">

          <level3>Some other Value</level3>

          <level3>Yet an other Value</level3>

        </level2>

      </level1>

    </data>

  </x:XData>

</xmldataprovider>


It's a three level hierarchy, and I want to display this data, by recursively selecting each level in a ListBox to see its content.

Now, let's bind this data to a list box, contained in a GroupBox to be a bit more readable :


<GroupBox Header="Level 1" DataContext="{Binding Source={StaticResource ops}}">

  <ListBox ItemsSource="{Binding}"

           DisplayMemberPath="@name"

           IsSynchronizedWithCurrentItem="True" />

</GroupBox>

This performs a binding to the attribute "name" of the level1 node list. The IsSynchronizedWithCurrentItem tells the listbox to set the CurrentItem of the current DataContext, which can be used to fill the next ListBox for the level.

Now, to add a new DataContext level, let's add a new GroupBox, and a stack panel to have a nice layout :


<GroupBox Header="Level 1"

          DataContext="{Binding Source={StaticResource ops}}">

  <StackPanel Orientation="Horizontal">

    <ListBox ItemsSource="{Binding}"

             DisplayMemberPath="@name"

             IsSynchronizedWithCurrentItem="True" />

    <GroupBox Header="Level2"

              DataContext="{Binding Path=CurrentItem}">

      <ListBox ItemsSource="{Binding}"

               DisplayMemberPath="@name"

               IsSynchronizedWithCurrentItem="True" />

    </GroupBox>

  </StackPanel>

</GroupBox>

Now, there is a new DataContext for any children of the second group box, and is having the CurrentItem of the upper DataContext as a root. This is fairly easy to do, so let's do this for the final level.


<GroupBox Header="Level 1"

          DataContext="{Binding Source={StaticResource ops}}">

  <StackPanel Orientation="Horizontal">

    <ListBox ItemsSource="{Binding}"

             DisplayMemberPath="@name"

             IsSynchronizedWithCurrentItem="True" />

    <GroupBox Header="Level2"

              DataContext="{Binding Path=CurrentItem}">

      <StackPanel Orientation="Horizontal">

        <ListBox ItemsSource="{Binding}"

                 DisplayMemberPath="@name"

                 IsSynchronizedWithCurrentItem="True" />

        <GroupBox Header="Level3"

                  DataContext="{Binding Path=CurrentItem}">

          <StackPanel Orientation="Horizontal">

            <ListBox ItemsSource="{Binding}"

                     IsSynchronizedWithCurrentItem="True" />

            <Label Content="{Binding Path=CurrentItem}" />

          </StackPanel>

        </GroupBox>

      </StackPanel>

    </GroupBox>

  </StackPanel>

</GroupBox>

Each time a new DataContext is set, a new CurrentItem is created. That kind of behavior was hard to reproduce using DataBinding with WinForms; WPF allows it only by using a simple declarative syntax. Easy and powerful.

Also there is a fine feature that came up when using this DataContext and CurrentItem : The CurrentItem "chain" for a specific path is -- when the data source does not change -- kept if you change the selection, and come back to that particular path. Pretty interesting.

Here is a working xaml sample of this post.

Did I say that a really like WPF already ? :)

WPF, Xml namespace and XmlDataProvider

By Jerome at January 30, 2007 16:15 Tags: ,

I was playing with the XmlDataProvider in WPF and I wanted to bind the content of inline XML from that provider to a ComboBox.

So, with I wrote this little piece of code :

<XmlDataProvider x:Key="ops" XPath="/operations/op">  <x:XData>    <operations>      <op>A</op>      <op>B</op>      <op>C</op>    </operations>  </x:XData></XmlDataProvider>[...]<ComboBox   ItemsSource="{Binding Source={StaticResource ops}}" />

Turns out that the combobox does not display anything, even though the XPath for the XmlDataProvider is correct and the ItemSource binding as well.

In reality, the problem is not in the binding but rather in the XPath, where the XML "operations" node in the inline xml inherits from the System.Windows XML namespace, which renders the XPath "/operations/op" ineffective. In that case, the XPath expression selects nodes from the "" (empty) namespace.

I just needed to write this instead :

<XmlDataProvider x:Key="ops" XPath="/operations/op">  <x:XData>    <operations xmlns="">

to reset the namespace used for that node, and my ComboBox was filled ! 

As a side note on WPF, I am just wondering on how this technology will be adopted. Many concepts are fairly innovative and differ from the usual concepts found in Winforms or even MFC.

I'm convinced that it is definitely going in the right direction with the data and design separation, but I'm not sure on how beginners are going to apprehend all this. Maybe a new release of Cider is going to ease development with this technology...Wait and see. 

Meanwhile, I'm continuing to enjoy the fact that I can databind a TreeView very easily :)

About me

My name is Jerome Laban, I am a Software Architect, C# MVP and .NET enthustiast from Montréal, QC. You will find my blog on this site, where I'm adding my thoughts on current events, or the things I'm working on, such as the Remote Control for Windows Phone.