DCSIMG
August 2010 - Posts - Pavel's Blog
Sign in | Join | Help

Pavel's Blog

Pavel is a software guy that is interested in almost everything
software related... way too much for too little time

August 2010 - Posts

WPF Auto Size ComboBox

Published at Aug 31 2010, 11:11 PM by pavely

One of the known issues with the WPF ComboBox is that its width is not set automatically to the widest element in the drop down list. This causes the width of the ComboBox to “jump” when the selected item changes.The simplest solution would be to set a Width explicitly, but this is not the “WPF way”, and will not work properly with different fonts and sizes, and generally is difficult to predict on a case by case basis.

Several solutions have been proposed, as evident in StackOverflow. Some of them suggest changing the default control template of the ComboBox, but I don’t like these kinds of solutions as they may work for a particular theme but not another, and generally are more difficult to implement, as the control template is usually quite complex.

The problem is that the ComboBox uses a Popup element to hold the list, but the popup is not opened until the first time the ComboBox is opened, thus making it difficult to predict the widest element in the popup.

The way I solved it involves creating a subclass of ComboBox, letting the ComboBox report its desired size when the selected index is zero. This gets me the “raw” width that includes mainly the drop down button. The next step is asking the Popup’s Content for its desired size (the Popup itself reports a desired size of zero, thus the need to ask its Content object), making the ComboBox MinWidth equal to its desired width plus the raw width. The last step involves restoring the selected index to its former value (if set in XAML or code). All this looks something like this:

public class ComboBoxEx : ComboBox {

   private int _selected;

 

   public override void OnApplyTemplate() {

      base.OnApplyTemplate();

 

      _selected = SelectedIndex;

      SelectedIndex = -1;

 

      Loaded += ComboBoxEx_Loaded;

   }

 

   void ComboBoxEx_Loaded(object sender, RoutedEventArgs e) {

      var popup = GetTemplateChild("PART_Popup") as Popup;

      var content = popup.Child as FrameworkElement;

      content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

      MinWidth = content.DesiredSize.Width + ActualWidth;

      SelectedIndex = _selected;

   }

 

}

 

This solution works for me, although I don’t like to derive a new class when no behavior change is required. This is not the “WPF way”. I plan to create a similar solution with the use of an attached property (something like “AutoSize”) that would mitigate the need for a derived class.

WPF 4 Tip: Setting the Target of a Label

Published at Aug 27 2010, 08:52 PM by pavely

The WPF Label control is a full blown ContentControl that can hold anything, but is mostly useful for holding text because of its ability to use an access key (ALT + key) causing the keyboard focus to move to a specified element by setting its Target property.

In WPF 3.x, you had to specify the element using a binding expression. For example:

 

<StackPanel Orientation="Horizontal" Margin="20">

     <Label Content="_Name: " Target="{Binding ElementName=txtName}" />

     <TextBox x:Name="txtName" Width="120" />

</StackPanel>

In WPF 4, you just need to supply the element’s name and you’re done (there is a new type converter that does the referencing for you):

<StackPanel Orientation="Horizontal" Margin="20">

     <Label Content="_Name: " Target="txtName" />

     <TextBox x:Name="txtName" Width="120" />

</StackPanel>

 

Happy labeling!

Silverlight Quirk: Content Alignment not respected for ListBox

Published at Aug 23 2010, 08:38 PM by pavely

Silverlight and WPF have many similarities, and many differences as well. One of the subtle ones I’ve discovered is with respecting the HorizontalContentAlignment property in a ListBox. Here’s the same application, written in WPF and Silverlight with the following ListBox (bound to a collection of Book objects) and its item template:

   <ListBox HorizontalContentAlignment="Stretch" x:Name="_list">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Red" BorderThickness="2">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <TextBlock Text="{Binding BookName}" FontSize="20" />
                        <TextBlock Grid.Row="1" Text="{Binding Author}" FontSize="16" Foreground="Blue" />
                    </Grid>
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

The results are:

WPF:

image

Silverlight:

image

Not quite the same.

For some reason, Silverlight’s ListBox template does not carry the HorizontalContentAlignment to the inner ListBoxItem objects.

Fortunately, the solution is simple: add an ItemContainerStyle property to the ListBox and set the HorizontalContentAlgnment to “Stretch”:

<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListBox.ItemContainerStyle>

The result:

image

My C# 5.0/CLR 5 Wish List

Published at Aug 22 2010, 01:54 PM by pavely

C# 5.0 is probably in the works (for sure). A while back I blogged about features I’d like to see in C# 4.0. I didn’t get any of my wishes (well, maybe I got one wish in an unexpected way, more on that later). Here’s a list of features I’d love to see in the next version of the C# language and the CLR. It’s not yet Christmas, but maybe Microsoft’s Santa needs some time to make these wishes come true:

operator constraints

This is something I wished for with C# 4.0, but didn’t get. Well, I actually did get it, but in an unexpected way. What I wanted is to used operators in a generic method:

public static T Sum<T>(params T[] values) {

   T sum = values[0];

   for(int i = 1; i < values.Length; i++)

      sum += values[i];

   return sum;

}

 

Unfortunately, this does not compile, as the compiler and CLR can’t be sure all Ts passed to the method have an addition operator. I would have wanted to add a constraint:

public static T Sum<T>(params T[] values) where T : operator+ {

 

However, currently no such constraint is supported. One possible reason is that operator overloading does not have to be implemented by a CLS compliant .NET language. On the other hand, all major languages support it, so maybe it should be permitted.

This actually can be done with the C# 4.0 dynamic keyword (without the need for generics). This is actually more flexible, because one can provide different types for addition (e.g. a Vector and a Point). Still, the runtime implications may be significant, so I want this constraint to be possible!

public static dynamic Sum(params dynamic[] values) {

   dynamic sum = values[0];

   for(int i = 1; i < values.Length; i++)

      sum += values[i];

   return sum;

}

 

Constructor inheritance

As we all know, constructors are not inherited with the usual inheritance in C#. I think that is unfortunate, as sometimes a class may have many constructors that one must duplicate to get a basic working class. The canonical example is an Exception derived class that must support at least 4 constructors. Perhaps there should be a way to inherit constructors (as is possible in C++0x, the new standard of C++).

Possible syntax for this could be a simple attribute that would make the compiler inherit all constructors and call the base class constructors blindly, or inheritance of specific constructors that could specified like so (without any need to introduce new keywords):

class A {

   public A() { ... }

   public A(int z) { ... }

   public A(int z, string s) { ... }

}

 

[InheritConstructors]

class B : A {

}

 

class C : A {

   using base(int);           // inherited constructor

   using base(int, string);   // inherited constructor

}

 

var working everywhere

Currently, the var keyword only works with local variables. This is unfortunate – I wish it would work with fields as well:

class Customer {

   private var _data = new Dictionary<string, int>();

   private var _name = string.Empty;

   private var _age = 20;

}

 

The last two examples are definitely an abuse of that feature, but it should be helpful in the first case. Although var was really created for anonymous types, I think its type inference capability alone is worth it.

 

delegate equivalence

Delegates types are synthesized by the compiler, deriving from System.MulticastDelegate, providing an appropriate Invoke method, etc. A delegate essentially defines a prototype, that can be declared in infinite ways. For example, the System.Action<object> is logically equivalent to System.Threading.WaitCallback, as both accept an object and return void.

However, any attempt to cast one delegate type to another with the same signature fails. Why should that be so? Since the compiler is the only entity generating those delegates, it (and the CLR) should be smart enough to allow conversion, as they are semantically the same.

The Func<> generic delegate is an attempt to reduce the number of delegates defined out there, a superset of delegates such as Predicate<>, but I believe that’s not enough. Delegate equivalence should help.

 

Const methods

This is bound to be heated. The const method issue has been probably beaten to death more than once, but still, I think the idea of const methods (as in C++) and their use through const objects is important, today more than ever, with the rising of functional languages and the benefits of immutability.

I believe the .NET developer community is mature enough to embrace it and love it.

 

This is my list so far, but I reserve the right to add more wishes as Christmas approaches…

Frame Based Animations in Silverlight

Published at Aug 11 2010, 12:30 PM by pavely

One way to do animations in Silverlight is to make gradual changes to dependency properties. Although this is powerful and convenient, it lacks in control. For example, developing a game with Silverlight may require complex movements of “bad guys” and other background elements that are not well suited for the property-based animation.

The alternative is frame-based animation. That is, every frame some change is applied to an element (such as the attached Canvas.Left and Canvas.Top properties, effectively moving the element around the containing canvas).

How should this be handled in Silverlight? How would we get a notification for every frame?

The most obvious solution is to use a DispatcherTimer object. Here’s a simple example:

DispatcherTimer timer;

 

public MainPage() {

   InitializeComponent();

   timer = new DispatcherTimer();

   timer.Interval = TimeSpan.FromMilliseconds(20);

   timer.Tick += OnMove;

   timer.Start();

}

The OnMove handler does all the changes required for some animation. Although this works, it’s difficult to set the “correct” timeout for the timer. It depends on the desired “frame rate”. In this example, it’s 1000/20=50 frames per second. This may be too much or too little, but worse than that, it’s unsynchronized with Silverlight’s updates (usually 60 fps but can be modified).

There is a better, more elegant way: set up a regular Storyboard that has a duration of zero and handle the Completed event. The handler will be called “immediately”, or more accurately, when Silverlight wants to update the display. This would be a good time to do those updates. Here’s an example:

    <UserControl.Triggers>
        <EventTrigger RoutedEvent="Control.Loaded">
            <BeginStoryboard>
                <Storyboard x:Name="move" Duration="0:0:0" Completed="Move_Completed" />
            </BeginStoryboard>
        </EventTrigger>
    </UserControl.Triggers>

 

Note the zero duration and the event handler. Inside the Completed handler, a call must be made to the Storyboard’s Begin method to “restart” the animation:

move.Begin();

 

There is a third way: using the CompositionTarget.Rendering static event. This is perhaps the simplest of them all – it’s called before Silverlight renders the next frame. Just put whatever needs to be updated in that handler and be done with it.

Happy animations!

Me at WebTech

Published at Aug 08 2010, 09:36 AM by pavely

The first WebTech conference is this Wednesday (the 11th of August), targeting web developers and other web authors. Technologies presented varies and are not limited to the Microsoft world. Java, PHP, Silverlight, ASP.NET, MVC, HTML, CSS and more.

I will be presenting an “Introduction to Silverlight Development” session. So, if you’re a web developer/designer and have not yet been exposed to Silverlight, this is your chance to see what Silverlight is and what can you do with it.

Maybe I’ll see you there!