views:

1073

answers:

3

I have the following ItemsControl in Silverlight 3.

<ItemsControl ItemsSource="{Binding ValueCollectionList}">
  <ItemsControl.ItemTemplate>
      <DataTemplate>

          <Button x:Name="MyBtn" Height="40" Content="{Binding Name}" 
              Tag="{Binding Value}"
              cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=ButtonCommand}"
              cmd:ButtonBaseExtensions.CommandParameter="{Binding ElementName=MyBtn, Path=Tag}"/>

      </DataTemplate>
   </ItemsControl.ItemTemplate>
 </ItemsControl>

The Problem is that I have the ItemsControl bound to the Collection in my ViewModel, but I need the button to trigger a command on the ViewModel which is of course not Available in the DataContext of the button since it only contains the collection.

I can make the command fire by setting my ViewModel as a Resource and then binding to it as a StaticResource, but I want to know why the element to element binding won't work in this scenario. I would prefer not to use the StaticResource binding because that requires the default constructor on the ViewModel and so I can't inject my data easily.

UPDATE

I'm working through this slowly... Looking at the suggestions from Peter I realized that I may have more serious binding issues because of my page setup. I have two possible road blocks, but first things first.

My Items control above is wrapped in another items control that is bound to an observable collection. I moved my items control so that its a direct child of the root items control. It was wrapped in another control that I'll get to. So I tried the element binding to the items control ControlItemList, but its a collection so it can't find my ButtonCommand method in that Collection. What I need to do is bind to an item within that collection. How do I bind to a single item within the collection?

<Grid x:Name="LayoutRoot" Background="White"><!-- DataContext="{Binding Path=., Source={StaticResource lvvm}}">-->
    <StackPanel Orientation="Vertical">
        <ItemsControl x:Name="ControlItemList" ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition MinWidth="100" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock x:Name="ControlName" Grid.Column="0"  Text="{Binding Name}" VerticalAlignment="Center" />
                        <ItemsControl  ItemsSource="{Binding ValueCollectionList}">
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>

So, Assuming I can get the above to work the other road block is that my items control is wrapped in another usercontrol that I'm using to get DataTemplateSelector type functionality. I think this control may be blocking me from getting to the parent DataContext. Is there a limit as to how far up the tree you can go?

<common:DeviceControlTemplateSelector Grid.Column="1" FieldType="{Binding ValueType}" Margin="0,2,0,2">
                            <common:DeviceControlTemplateSelector.StringTemplate>
                                <DataTemplate>
                                    <TextBox Text="{Binding Value, Mode=TwoWay}" Width="100"/>
                                </DataTemplate>
                            </common:DeviceControlTemplateSelector.StringTemplate>
                            <common:DeviceControlTemplateSelector.DateTimeTemplate>
                                <DataTemplate>
                                    <TextBox Text="this is date time binding" Width="100"/>
                                </DataTemplate>
                            </common:DeviceControlTemplateSelector.DateTimeTemplate>
                            <common:DeviceControlTemplateSelector.BooleanTemplate>
                                <DataTemplate>
                                    <CheckBox IsChecked="{Binding Value, Mode=TwoWay}" />
                                </DataTemplate>
                            </common:DeviceControlTemplateSelector.BooleanTemplate>
                            <common:DeviceControlTemplateSelector.IntegerTemplate>
                                <DataTemplate>
                                    <ComboBox ItemsSource="{Binding ValueCollection}" DisplayMemberPath="Value" SelectedIndex="{Binding Value, Mode=TwoWay}" >

                                    </ComboBox>
                                </DataTemplate>
                            </common:DeviceControlTemplateSelector.IntegerTemplate>
                            <common:DeviceControlTemplateSelector.MultiButtonTemplate>
                                <DataTemplate>
                                        <ItemsControl ItemsSource="{Binding ValueCollectionList}">
                                            <ItemsControl.ItemTemplate>
                                                <DataTemplate>

                                                    <Button x:Name="MyBtn"
                                                            Height="40" Content="{Binding Name}" 
                                                            Tag="{Binding Value}"
                                                            cmd:ButtonBaseExtensions.Command="{Binding ElementName=ControlItemList, Path=DataContext.ButtonCommand}"                                                               
                                                            cmd:ButtonBaseExtensions.CommandParameter="{Binding Value}"/>
                                                </DataTemplate>
                                            </ItemsControl.ItemTemplate>
                                        </ItemsControl>
                                </DataTemplate>
                            </common:DeviceControlTemplateSelector.MultiButtonTemplate>

                                    <Button x:Name="MyBtn"
                                                            Height="40" Content="{Binding Name}" 
                                                            Tag="{Binding Value}"
                                                            cmd:ButtonBaseExtensions.Command="{Binding ElementName=ControlItemList, Path=ButtonCommand}"                                                               
                                                            cmd:ButtonBaseExtensions.CommandParameter="{Binding Value}"/>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>

Thanks again everyone for your help!

A: 

In MVVM messaging is a strong concept for cummunication between ViewModels. You could use PRISM Eventaggregator or the Messenger class of MVVM Light Toolkit. On the button command you can publish a message and subscribe to it in the viewmodel.

silverfighter
Thank you silverfighter for the post, but I really would like to understand why my code above doesn't work. I may have to go the messaging route or making the ViewModel a staticresource, but I'm not understanding why I can't access the parent objects datacontext from within my itemscontrol.
BigTundra
A: 

Try to change
from

cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=ButtonCommand}"

to

cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=DataContext.ButtonCommand}"

OR

cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot.DataContext, Path=ButtonCommand}"

Peter Gfader
I'm not able to get this to work because the DataContext of the LayoutRoot is an ObservableCollection, so when I try to bind to my ButtonCommand method I get...System.Windows.Data Error: BindingExpression path error: 'ButtonCommand' property not found on 'System.Collections.ObjectModel.ObservableCollection`1[Chopper.Common.DeviceControlViewModel]' 'System.Collections.ObjectModel.ObservableCollection`1[Chopper.Common.DeviceControlViewModel]' (HashCode=26753075). BindingExpression: Path='DataContext.ButtonCommand' DataItem='System.Windows.Controls.ItemsControl'How can I bind to the item?
BigTundra
A: 

the best solution i have found so far to deal with this situation is by Dan Wahl where he uses a DataContextProxy.

http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx

Nick