Ivan Krivyakov's Blog

Premature optimization is the root of all evil

August 24, 2010

Can’t have a binding to binding

Let’s say we want to display a list of countries, and depending on the user input we want to show either the capital city, population, or the language spoken in the country alongside the country name, like in the application below:

Dynamic binding screen shot

The only way to achieve that is to change binding in code. You cannot have something like

<Binding Path="{Binding SelectedField}" />

because Path is not a dependency property. :(

August 13, 2010

WPF: Merged dictionary parser depends on XML attribute order

Does attribute order in XAML matter? It should not, but sometimes it does. The following XAML compiles, but blows up at runtime with “Item has already been added” exception, both in .NET 3.5 and .NET 4.0:

<Window x:Class="MergedDictionaryKeyPosition.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
  <Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary>
                <Style TargetType="Button" x:Key="foo" />
                <Style TargetType="Button" x:Key="bar" />
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries> 
   </ResourceDictionary>
  </Window.Resources>

  <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Hello" />
</Window>

What’s wrong with it? [read more...]

April 14, 2010

WPF drag and drop

I think I have finally found one that seems to do everything I need. This is quite an elaborated piece of software, I am only starting to investigate it, but the demo looks very promising:

http://www.codeproject.com/KB/WPF/gong-wpf-dragdrop.aspx

UPD: Indeed, great stuff. One of the best drag-and-drop solutions out there.

WPF: Context menu on list item

I am using WPF and MVVM. I have a Window and a view model attached to it via Datacontext. The window has a listbox, and its items have context menu. I am using DelegateCommand in my view model, and I want to bind a menu items in the context menu to this command.

First trouble is, by default the menu item is bound to the DataContext of the list box item, which may or may not have knowledge of the whole view model.

Second trouble is, context menu is not part of the visual tree, so referring to the main window via FindAncestor or ElementName=... will not work.

You can get to the object immediately containing the context menu via the PlacementTarget property, but then you will need an ancestor of this object (“window”), and there is no built-in way to find an ancestor of a property.

An (almost) working solution that I found on the Internet after hours of search was to store the data context some property of the PlacementTarget – they used Tag for this purpose.

The “almost” part lies in the fact that if your command has CanExecute() method, the command parameter passed to it is sometimes null (see here).

<Window Name="MainWindow" ...>
    <Grid>
        <ListBox ItemsSource="{Binding Items}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal"
                               Tag="{Binding DataContext, ElementName=MainWindow}">
			...
                        <StackPanel.ContextMenu>
                             <MenuItem Header="do it"
    Command="{Binding PlacementTarget.Tag.MyCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
    CommandParameter="{Binding}">
                        </StackPanel.ContextMenu>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

April 7, 2010

WPF/C#: in desperate need of macros

As I mensioned earlier on Microsoft forums (with no response), we desperately need some kind of macro language. I am now developing some GUI using WPF. WPF is a very structured system, but look how many thigns I need to do to route a simple command:

1. In my view model class I add
private DelegateCommand<object> _groupDeleteCommand;
public DelegateCommand<object> GroupDeleteCommand
{ get { return _groupDeleteCommand; } }

2. Then in the constructor of said class I need to add
_groupDeleteCommand = new DelegateCommand<object>(OnGroupDelete);

3. Then in the body of the class I need to add
private void OnGroupDelete(object arg)
{
}

4. Then in the XAML file I need to add
<MenuItem Command="{Binding GroupDeleteCommand}" />

Rinse and repeat for every command in the command list. This is a lot of duplication. Truckloads of it. I am so annoyed, I took time to write this blog post.

March 19, 2010

How to embed arbitrary content in a WPF control

This is one of those thigns where trivial and easy solution does not work, and in the process you find out that the philosophy is totally different from what you thought. Finally finished and published.

September 20, 2009

Emissive Material Troubles

It turns out that emissive material is quite a tricky fellow. Petzold’s book warns not to use EmissiveMaterial by itself, and always combine it with a diffuse material, which may be black. Otherwise, “the results are not satisfactory”. I found out firsthand what “not satisfactory” results may look like.

It turns out that behavior of “Emissive-only” material is not consistent for different shapes. Furthermore, if you combine diffuse material with emissive material, the diffuse material should come first, or else it negates effect of the emissive material. I suspect some very sloppy code inside WPF 3D, or maybe there is some hidden very important reason why it is what it is.

I wrote a little application that demonstrates the issue on various shapes. Here’s the summary of the results:

Geometry Front Back Result
Cube Diffuse   OK
Cube Emissive   Nothing visible
Cube Emissive Diffuse OK
Cube Emissive+Diffuse   Black cube
Cube Diffuse+Emissive   OK
Triangle Diffuse   OK
Triangle Emissive   Nothing visible
Triangle Emissive Diffuse Nothing visible
Triangle Emissive+Diffuse   Black triangle
Triangle Diffuse+Emissive   OK

Note the inconsistency: a cube with emissive front and diffuse back is visible, while the triangle is not. The right thing to do is to define the material as a group having a diffuse and an emissive component, with the diffuse component always coming first.

I also have reasons to believe that Emissive-only sphere is visible, but is transparent: the objects behind it will show through. However, I am not sure whether this is an artifact of a particular sphere implementation, a particular scene, or a property of complex emissive bodies in general.

September 13, 2009

WPF: Making Objects Invisible

This is not as easy as it might have been. There is no Visible property on ModelVisual3D or GeometryModel3D. Approaches considered in this discussion on the Microsoft site include making material brushes transparent or having a transform on the object moving it out of the way.

Fiddling with brushes leads to problems. First, base Material class does not expose the Brush property, so you must hunt for a concrete material such as DiffuseMaterial to get the actual brush. Second, the poster reports issues with objects other than the intended object getting partially invisible, etc.

The approach with transforms “to nowhere” seems more attractive, but it kinda reminds me of the days when people put windows at “large” negative coordinates (say -1000,-1000) to make them “invisible”. It worked fine for a while, but turned out quite ugly when 1200×1024 double-monitor setups became common. If you make your right monitor a primary, the left monitor gets negative coordinates, and you suddenly see all those windows crowded in the bottom of your screen.

September 12, 2009

Animated properties in view model: update

I received a response to my question on the Microsoft WPF forum.

Will investigate and report the results here.

September 1, 2009

WPF: Cannot Combine Bindings and Other Text

It is not a big deal, but still unpleasant. It is not possible to do something like

<TextBlock Text=”Speed: {Binding Path=Speed} mph” />

The text in the squiggles appears verbatim on screen, the binding does not occur. Instead, one needs to write

<TextBlock>Speed: <TextBlock Text=”{Binding Path=Speed}” /> mph</TextBlock>

This requires significant amount of extra typing when writing, and creates serious clutter when reading. Not a big deal, but disappointing. A better solution would be to parse expressions like this and do the bindings. Of course, there will be implications: if one really wants a squiggle, they will have to escape it, just like in String.Format. Also, when looking for bindings and other extensions, WPF will have to scan the whole text instead of just checking the first character. I am not sure how serious this is, but it does not sound very ominous. I suspect WPF authors just did not have time to implement this advanced parsing.