views:

34

answers:

1

I'm working on an application that uses a richly formatted ListBox. One of the things I need is to bind multiple pieces of information to a button that lives within the ListBox's DataTemplate.

This is an over-simplification of my actual code that I made to help you understand the problem.

Here's a chunk of XAML from inside the DataTemplate that works:

<Button Command="local:MediaCommands.StreamVideo"
    CommandParameter="{Binding Path=Folder}" />

When I press the button, it sends the Folder property of the data item that this list is based around (the member of ItemsSource that the current list item is showing). However, I need another piece of data, the Filename property of the current item. To accomplish this, I set up a new class, FileInfo, that contains dependency properties for Folder and Filename. I then replaced the XAML code before with:

<Button Command="local:MediaCommands.StreamVideo">
    <Button.CommandParameter>
        <data:FileInfo Folder="{Binding Path=Folder}"
            Filename="{Binding Path=Filename}" />
    </Button.CommandParameter>
</Button>

However, the only thing that my code is sending me is a blank FileInfo object. Note that if I change the XAML above to include literal values for Folder and Filename, the code works fine, in the sense that it correctly creates the FileInfo object and assigns the correct properties.

For reference, my FileInfo class looks a bit like this:

class FileInfo : DependencyObject {
    public static readonly DependencyProperty FolderProperty;
    public static readonly DependencyProperty FilenameProperty;
    static FileInfo() {
        FolderProperty = DependencyProperty.Register("Folder",
            typeof(string), typeof(FileInfo));
        FilenameProperty = DependencyProperty.Register("Filename",
            typeof(string), typeof(FileInfo));
    }
    public string Folder {
        get { return (string) GetValue(FolderProperty); }
        set { SetValue(FolderProperty, value); }
    }
    public string Filename {
        get { return (string) GetValue(FilenameProperty); }
        set { SetValue(FilenameProperty, value); }
    }
}

Ignoring the fact that, in this case, I could simply pass a reference to the data object itself (in my actual application, I need to draw data from a couple nested ListBoxs, but the issue is the same), can anybody see what is going on here? Have my dependency properties not been declared properly? Do I need to do something quirky with the bindings?

+3  A: 

Bindings that don't explicitly declare a Source rely on the DataContext as their Source. You haven't declared a DataContext on the FileInfo instance, which would normally mean that an inherited DataContext would be used. DataContext inheritance depends on both FrameworkElement and the runtime Visual Tree, neither of which come into play when you're using a non-FrameworkElement derived class assigned to a property that doesn't display in the tree.

John Bowen
I tried making `FileInfo` inherit from `FrameworkElement` instead of `DependencyObject`, but that didn't fix the problem. Did I misread your solution?
Ethan
John did mention also that the object must be part of the Visual Tree in order to make DataContext inheritance work. In your case, FileInfo isn't. So it does not pick up the DataContext. Anyway, one possible solution for what you have above is to have an IValueConverter that returns a FileInfo instance given your data class. In doing so, your CommandParameter will then be declared as <Button CommandParameter="{Binding Converter=MyFileInfoConverter}"/>.
karmicpuppet
The issue I see with that (and it may be a non-issue) is that my data isn't just coming from my data class. Rather, I need a field from my data class and two fields from other elements (`ListBox`s) within the data template. Strictly speaking, I could simply return no parameter and program the button's callback so it walks through the element tree, but that would take a lot of work and would be horribly inelegant. I feel like there should be a better solution.
Ethan
To get data from multiple objects you can still use @karmicpuppet's suggestion but use a MultiValueConverter to pass in multiple bound values for building your FileInfo object.
John Bowen