Archive | January, 2009

Docking WPF controls to right or bottom of a Canvas

28 Jan

When first learning WPF one thing that stumped me was docking controls to the right hand side of a canvas. As I understand WPF layouts, the only default WPF control that allows controls to overlap is the canvas layout control (See comments about a correction here. The canvas control is not the only control that allows items to overlap). This is why I was forced to use the canvas layout (as I wanted the ability to place controls over the top of each other).

The way to solve this issue was to use a multibinding and a multibinding converter. I have provided a code sample below showing a treeview control that is docked to bottom right side of a wpf window.

<TreeView x:Name="Menu" DataContext="MenuData" Height="350" Width="220">
  <Canvas.Left>
    <MultiBinding Converter="{StaticResource RelativePlacementConverter}">
      <Binding ElementName="MainCanvas" Path="ActualWidth" />
      <Binding ElementName="Menu" Path="ActualWidth" />
    </MultiBinding>
  </Canvas.Left>
  <Canvas.Top>
    <MultiBinding Converter="{StaticResource RelativePlacementConverter}">
      <Binding ElementName="MainCanvas" Path="ActualHeight" />
      <Binding ElementName="Menu" Path="ActualHeight" />
    </MultiBinding>
  </Canvas.Top>
</TreeView>

public class RelativePlacementConverter : IMultiValueConverter

{

#region IMultiValueConverter Members

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

double? screenWidth = values[0] as double?; //parent width

double? menuWidth = values[1] as double?; //own width

if (screenWidth != null && menuWidth != null)

{

return (screenWidth – menuWidth);

}

return 0.0;

}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)

{

throw new NotImplementedException();

}

#endregion

}

The previous code uses the width and height of the treeview control called Menu and subtracts that from the width and height of the canvas called MainCanvas. For more usecases or more depth on how to implement a multibinding I recommend the following: wpf-tutorial-using-multibindings.

I would recommed using multibindings when a value needs to be result of a combination of other values. There are other ways around this issue without using a multibinding. Links to APIs to avoid multibindings are avalible at: http://marlongrech.wordpress.com/2008/02/10/embed-code-in-xaml/. I like the idea of avoiding multibindings as they take a bit more effort that should be required for simple scenarios like this blog post, however I am also sceptical of alternatives because they don’t yet seem to leverage the power of code behind the way that the multivalueconverter allows.

Linq Anonymous return types

21 Jan

I have decided to make a post about LINQ anonymous types with respect to typing after talking to some colleagues. Below I compare 2 LINQ statements, the first being with an anonymous type being returned, the second with a specified type being returned.

Anonymous type:

IList<Window> windows = new List<Window>();

var query = from window in windows

where window.Visibility == Visibility.Hidden

select new

{

Visibility = window.Visibility,

Title = window.Name

};

image

Specified Type:

IList<Window> windows = new List<Window>();

var query = from window in windows

where window.Visibility == Visibility.Hidden

select new myType

{

Visibility = window.Visibility,

Title = window.Name

};

image

Comparing the two return types shown in both of the images, we can see that both return the same data. The thing we cannot see is that an anonymous type is scoped to the method that the LINQ statement is in. This means that we can’t pass query off to another method unless we extract the data we want to a non anonymous type.

C# variable naming

15 Jan

From working in a team environment, I have learnt of a number of different ways of naming variables. Reading this post it could be thought that variable naming schemes are purely preference, however I believe that there are some arguments against certain schemes. Take for example:

        private String str;

        public void Method1(String str)

        {

            this.str = str;

        }

 

If you use a plugin called Resharper  like I do then the method input is highlighted because it hides str. I have more of an issue with the following potential mistake:

        private String str;

        public void Method1()

        {

            this.str = str;

        }

 

The previous code is still valid with the compiler, however it is clear that str is not going to be populated, however a tool such as resharper will not make you aware that the this.str is never assigned.

The approach that I use for code sample 1 would be:

        private String _str;

        public void Method1(String str)

        {

            _str = str;

        }

 

The underscore ‘_’ is used for member/class wide variables. If we are to replicate code sample 2 with the underscore naming scheme we will get the following result:

        private String _str;

        public void Method1()

        {

            _str = str;

        }

We can clearly see that this code will not compile. We can also observe that the underscore notation is more compact by not requiring the ‘this’ keyword.

Another two reasons I like the underscore naming convention are:

 

  1. Intellisense grouping. Press underscore key and intellisense will group all member variables together.

  2. No confusion as to the availability of a variable. If it has underscore it is available class-wide. If it doesn’t it is only available within that method.

I have seen other people use m_VariableName but I think that just using an underscore is better because it is shorter, and the intellisense is grouped better because it is at the start of the intellisense list. Another alternative naming scheme involves putting the type in the variable name. I would advice against this because tools like resharper can tell a user what type a variable is in design time, and implicit typing will likely destroy the naming scheme.

List Conversion

9 Jan

One of my favourite use cases for lambda expressions in .NET is converting lists. Take the following code as an example:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows;

 

namespace LambdaComparison

{

    public partial class Window1 : Window

    {

        public Window1()

        {

            InitializeComponent();

 

            IList<Person> people = new List<Person>();

 

            Example1(people);

            Example2(people);

        }

 

        public void Example1(IList<Person> people)

        {

            var names = people

                          .Select(item => item.Name).ToList();

        }

 

        public void Example2(IList<Person> people)

        {

            var names = new List<String>();

 

            foreach (var person in people)

            {

                names.Add(person.Name);

            }

        }

    }

 

    public class Person

    {

        public String Name

        {

            get; set;

        }

    }

}

From using this approach for converting lists between types I have found that it leads to more readable code, as it is one line rather than many.

One other thing that is worth noting and is very important tip when using LINQ or lambda expressions, is that the return type is IEnumerable<T>. Often when using LINQ etc it is common for people to expect a list or use the "var" keyword. The var keyword is not actually a type but rather is implicitly typed which means that the compiler infers/computes the type based on the right hand side of an assignment. I usually use var but i had issues with more complex LINQ statements until I realised how to understand what the var keyword was representing and how it was being deduced (which is not immediately obvious for beginners with many LINQ statements). LINQ also offers the ability to create annonymous types which provide challenges in the area of non implicit typing.