Ivan Krivyakov's Blog

Premature optimization is the root of all evil

April 29, 2010

Once more about macros in C#

I am writing a WPF app. In WPF they like very much all kinds of notifications about property changes. Thus, I’ve got a class with a bunch of properties similar to this:

    class Person
    {
        void OnPropertyChanged(string propertyName)
        {
        …
        }
 
        public string LastName
        {
            get { return _lastName; }
 
            set
            {
                if (_lastName != value)
                {
                    _lastName = value;
                    OnPropertyChanged("LastName");
                }
            }
        }
        string _lastName;
 
        public int Age
        {
            get { return _age; }
 
            set
            {
                if (_age != value)
                {
                    _age = value;
                    OnPropertyChanged("Age");
                }
            }
        }
        int _age;
    }

This is long, boring, and bloated. Of course, I created a code snipped for generating the properties, but it works only once, at the time of writing, the code is still bloated, and all the changes must be done by hand. Besides, it is unable to change case automatically, so that Age becomes _age.

I would like to see something like:

    class MyClass
    {
        public Observable<string> LastName;
        public Observable<int> Age;
    }
 
    property Observable<T>
    {
        T _value;
        get { return _value; }
        set
        {
            if (_value != value)
            {
                _value = value;
                OnPropertyChanged(#PropertyName);
            }
        }
    }

Of course, the syntax is approximate. Unfortunately, nothing of the sort exists. Generics are of no help here, and there are no macros in C#.

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 in 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 8, 2010

Test of cross-post to Live Journal

This is a post to my mostly programming blog, let’s see if it shows up in LJ

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.

April 2, 2010

.NET: It is possible to apply attributes to enum members

For a long time I was sure it is not supported, because there was no corresponding AttributeTargets value.

It turns out, that you can do it by using AttributeTargets.Field. Declaring your attribute class:

[AttributeUsage(AttributeTargets.Field)]

public class CategoryAttribute : Attribute

Declaring your decorated enum:

enum MyEnum

{

    [Category("foo")]

    Foo,

 

    [Category("This is bar")]

    Bar,

 

    Baz

}

Reading attribute values:

foreach (MyEnum x in Enum.GetValues(typeof(MyEnum)))

{

    MemberInfo[] info = typeof(MyEnum).GetMember(x.ToString());

    if (info.Length != 1)

    {

        Console.WriteLine("Get {0} members for {1}", info.Length, x);

        continue;

    }

 

    Attribute[] categories = Attribute.GetCustomAttributes(info[0], typeof(CategoryAttribute));

    if (categories.Length == 0)

    {

        Console.WriteLine("{0}: No category", x);

    }

    else

    {

        CategoryAttribute category = (CategoryAttribute)categories[0];

        Console.WriteLine("{0}: {1}", x, category.Category);

    }

}