Silverlight3 ItemsControl中的MVVM绑定以获取父控件DataContext

时间:2010-04-01 19:06:21

标签: silverlight data-binding silverlight-3.0 mvvm

我在Silverlight 3中有以下ItemsControl。

<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>

问题是我在ViewModel中将ItemsControl绑定到Collection,但是我需要按钮来触发ViewModel上的命令,该命令当然在按钮的DataContext中不可用,因为它只包含集合。

我可以通过将我的ViewModel设置为Resource然后将其作为StaticResource绑定到它来激活命令,但我想知道为什么元素绑定的元素在这种情况下不起作用。我宁愿不使用StaticResource绑定,因为它需要ViewModel上的默认构造函数,所以我不能轻易地注入我的数据。

更新

我正在慢慢地解决这个问题......看看彼得的建议我意识到由于我的页面设置,我可能会遇到更严重的绑定问题。我有两个可能的障碍,但首先是第一件事。

上面的My Items控件包含在绑定到可观察集合的另一个item控件中。我移动了我的项控件,使其成为根项控件的直接子项。它包裹在另一个控件中,我会去。所以我尝试将元素绑定到item控件ControlItemList,但它是一个集合,因此它无法在该Collection中找到我的ButtonCommand方法。我需要做的是绑定到该集合中的项目。如何绑定到集合中的单个项目?

<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>

所以,假设我能够完成上述工作,那么另一个障碍就是我的items控件被包装在另一个用于控件的控件中,我用它来获取DataTemplateSelector类型的功能。我认为这个控件可能会阻止我访问父DataContext。你可以去树的距离有限制吗?

<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>

再次感谢大家的帮助!

3 个答案:

答案 0 :(得分:3)

到目前为止我发现的解决这种情况的最佳解决方案是由Dan Wahl使用DataContextProxy。

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

答案 1 :(得分:1)

尝试更改
来自

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

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

OR

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

答案 2 :(得分:0)

在MVVM中,消息传递是ViewModels之间的强大概念。您可以使用PRISM Eventaggregator或MVVM Light Toolkit的Messenger类。在按钮命令上,您可以发布消息并在viewmodel中订阅它。