0

I have a listbox which binds to a observable collection in my view model (the user controls data context).

DeviceDetector driveDetector;
public DriveSelector()
{
    InitializeComponent();

    driveDetector = DeviceDetector.Instance;
    DataContext = driveDetector;
}

This is my code for my listbox

<ListBox Style="{StaticResource ListBoxStyle}" ItemsSource="{Binding DriveCollection}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Button Width="70" Style="{StaticResource DriveButtonStyle}" Command="{Binding SimpleMethod}">
                                <StackPanel>
                                    <Image Source="{Binding Image}" Style="{StaticResource DriveImageStyle}"/>
                                    <Label Content="{Binding Name}" Style="{StaticResource DriveLabelStyle}"/>
                                </StackPanel>
                            </Button>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

I have implemented ICommand and when i bind to the command outside of the listbox like so:

<Button Command="{Binding SimpleMethod}"/>

Everything is fine. However when i try to bind the command to the button's inside the listbox's datatemplate i get this error:

System.Windows.Data Error: 40 : BindingExpression path error: 'SimpleMethod' property not found on 'object' ''DriveInfo' (HashCode=6377350)'. BindingExpression:Path=SimpleMethod; DataItem='DriveInfo' (HashCode=6377350); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')

I can see that the datacontext of the button is to the model and so the method 'SimpleMethod' cannot be found. Is there a way that i can bind the command to the datacontext of the listbox itself?

Timmoth
  • 480
  • 2
  • 18
  • You could write a custom behavior for your button. This way you'll bind it to your button. Don't know, when should this method be fired? – Christoph K Mar 31 '16 at 11:28

3 Answers3

1

You can reference the window or page top level DataContext like this:

 <Button Content="{StaticResource Whatever}"
      DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Page}}"
      CommandParameter="{Binding}"
      Command="{Binding SimpleMethod}" />
Crowcoder
  • 11,250
  • 3
  • 36
  • 45
  • It's enough to get `DataContext` of `ListBox`. Also, you forgot `Path=SimpleCommand` in your binding. This should be an accepted answer after imho. Small note: either remove `CommandParameter` (OP seems don't need it) or move it **before** `Command` (see [here](http://stackoverflow.com/a/336258/1997232) why it is important). – Sinatr Mar 31 '16 at 12:09
  • @Sinatr, thanks for the tip. But I don't use `Path` in my command that I took this code from, and it works fine. – Crowcoder Mar 31 '16 at 12:13
  • 1
    You are right, for some weird reasons (sorry for my previous comment then) I haven't seen you are reassigning `DataContext`. Don't do that. Rather use `RelativeSource` in `Command` binding itself: `Command="{Binding DataContext.SimpleMethod, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}"`. – Sinatr Mar 31 '16 at 12:19
  • @Sinatr, what is the reasoning for that? If I reassign the context then I could use it on any number of attributes without having to do RelativeSource on each, right? Is it a performance/efficiency issue? – Crowcoder Mar 31 '16 at 12:26
  • Good question. For me not touching `DataContext` in the world of data templates is an axiom. Perhaps to avoid situation like [this](http://stackoverflow.com/q/5155852/1997232). Can't say anything about performance. – Sinatr Mar 31 '16 at 12:40
0

What is owner of SimpleMethod? DataContext or item of collection? I suspect that DataContext. Move SimpleMethod to item class from DataContext class. Or use RelativeSource like this Bind to ItemsControl's DataContext from inside an ItemTemplate

Community
  • 1
  • 1
Denis Fedak
  • 161
  • 12
0

How i managed to solve my problem:

Firstly i created a static resource of my view model. Then bound it to my datacontext in xaml

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/Styles;component/Resources.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <vm:DeviceSelectorViewModel x:Key="myViewModel" x:Name="myVM" />
    </ResourceDictionary>
</UserControl.Resources>

<UserControl.DataContext>
    <StaticResourceExtension ResourceKey="myViewModel"/>
</UserControl.DataContext>

Which allowed me to then change the source of the command to the (static resource) view model like so:

<Button Width="70" Style="{StaticResource DriveButtonStyle}" Command="{Binding SimpleCommand, Source={StaticResource myViewModel}}" >

Thanks for the replies!

Timmoth
  • 480
  • 2
  • 18