【问题标题】:MVVM Binding in Silverlight3 ItemsControl to get the parent controls DataContextSilverlight3 ItemsControl中的MVVM绑定获取父控件DataContext
【发布时间】:2011-02-03 12:15:25
【问题描述】:

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

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

我可以通过将 ViewModel 设置为 Resource 然后将其作为 StaticResource 绑定到它来触发命令,但我想知道为什么元素到元素的绑定在这种情况下不起作用。我不希望使用 StaticResource 绑定,因为这需要 ViewModel 上的默认构造函数,因此我无法轻松注入数据。

更新

我正在慢慢解决这个问题...看着 Peter 的建议,我意识到由于我的页面设置,我可能会遇到更严重的绑定问题。我有两个可能的障碍,但首先要做的是。

上面的我的 Items 控件被包装在另一个绑定到可观察集合的 items 控件中。我移动了我的项目控件,使其成为根项目控件的直接子项。它被包裹在另一个控件中,我将得到它。因此,我尝试将元素绑定到项目控件 ControlItemList,但它是一个集合,因此它无法在该集合中找到我的 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>

所以,假设我可以让上述工作正常工作,另一个障碍是我的项目控件被包装在另一个用户控件中,我用来获取 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>

再次感谢大家的帮助!

【问题讨论】:

    标签: silverlight data-binding silverlight-3.0 mvvm


    【解决方案1】:

    到目前为止,我发现处理这种情况的最佳解决方案是 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

    【讨论】:

      【解决方案2】:

      尝试改变
      来自

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

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

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

      【讨论】:

      • 我无法让它工作,因为 LayoutRoot 的 DataContext 是一个 ObservableCollection,所以当我尝试绑定到我的 ButtonCommand 方法时,我得到...System.Windows.Data 错误: BindingExpression 路径错误:在“System.Collections.ObjectModel.ObservableCollection1[Chopper.Common.DeviceControlViewModel]' 'System.Collections.ObjectModel.ObservableCollection1[Chopper.Common.DeviceControlViewModel]”上找不到“ButtonCommand”属性(HashCode=26753075)。 BindingExpression: Path='DataContext.ButtonCommand' DataItem='System.Windows.Controls.ItemsControl' 如何绑定到项目?
      【解决方案3】:

      在 MVVM 中,消息传递是 ViewModel 之间交流的一个强有力的概念。您可以使用 PRISM Eventtaggregator 或 MVVM Light Toolkit 的 Messenger 类。在按钮命令上,您可以发布消息并在视图模型中订阅它。

      【讨论】:

      • 感谢 silverfighter 的帖子,但我真的很想了解为什么上面的代码不起作用。我可能必须走消息传递路线或使 ViewModel 成为静态资源,但我不明白为什么我不能从我的 itemscontrol 中访问父对象 datacontext。
      • EventAggregator 在单个 ViewModel(更不用说模块)中的消息传递是否过度杀伤?
      猜你喜欢
      • 1970-01-01
      • 2012-01-19
      • 2014-07-30
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 2013-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多