【问题标题】:Access parent datacontext in listbox in Silverlight在 Silverlight 的列表框中访问父数据上下文
【发布时间】:2008-12-22 08:25:10
【问题描述】:

在 Silverlight 2 中,我使用了一个用户控件,它继承了它所嵌入的页面的数据上下文。此数据上下文包含问题文本、问题类型和答案集合。在用户控件中有一个列表框,它绑定到答案集合。如下图:

<ListBox DataContext="{Binding}" x:Name="AnswerListBox" ItemContainerStyle="{StaticResource QuestionStyle}" Grid.Row="1" Width="Auto" Grid.Column="2" ItemsSource="{Binding Path=AnswerList}" BorderBrush="{x:Null}" />       

这个列表框有一个关联的样式,以单选按钮或复选框的形式显示答案(我想根据问题类型隐藏或显示):

<Style TargetType="ListBoxItem" x:Key="QuestionStyle">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">                      
                        <StackPanel Background="Transparent" >
                            <RadioButton Visibility="{Binding Path=QuestionType, Converter={StaticResource QuestionTypeConverter}, ConverterParameter='RadioButtonStyle'}" Height="auto" Margin="0,0,0,10"  IsChecked="{TemplateBinding IsSelected}" IsHitTestVisible="False" Content="{Binding Path=AnswerText}">
                            </RadioButton>
                            <CheckBox Visibility="{Binding Path=QuestionType, Converter={StaticResource QuestionTypeConverter}, ConverterParameter='CheckBoxStyle'}" Height="auto" Margin="0,0,0,10" Content="{Binding Path=AnswerText}">
                            </CheckBox>
                        </StackPanel>                                                
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

那么我的问题是:如何访问父数据上下文以获取 QuestionType(因为这是用户控件数据上下文本身的属性,而不是 AnswerList 中 AnswerItem 的属性)?

或者,有没有更好的方法可以根据绑定值在 xaml 中动态切换样式?

【问题讨论】:

  • 您有什么方法可以更改您接受的答案吗?下面是 Roboblob 的一个正确答案。接受的答案对于 Silverlight 是不正确的并且具有误导性。

标签: silverlight-2.0


【解决方案1】:

在 Silverlight 3 和更高版本中,您可以使用 Element 到 Element 绑定并指向控件 DataContext,然后在我的示例中指向其 Threshold 属性。

所以首先命名您的控件(例如在我的示例中它的 x:Name="control")

<UserControl x:Class="SomeApp.Views.MainPageView" x:Name="control" >

然后在您的 ListBox ItemTemplate 中的此控件内,您可以像这样访问父 DataContext:

    <ListBox ItemsSource="{Binding Path=SomeItems}" >
        <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding ElementName=control, Path=DataContext.Threshold}"/>
            </StackPanel>
        </DataTemplate>
       </ListBox.ItemTemplate>         
       </ListBox>

【讨论】:

  • 重要的是不要错过您需要明确放入“DataContext”。我之前放弃了这样做的尝试,因为我设法忘记放置'DataContext'
  • @roboblob - 你碰巧知道在 DataForm 中执行此操作的好方法吗(与我在下面的帖子中显示的方式不同)
  • @Roboblob - 一个常见问题的巧妙解决方案。我将对标记为“the”的答案投反对票,因为它具有误导性,实际上浪费了我们的时间,直到我们看到你的答案。
  • 这个解决方案看起来非常优雅,但不幸的是我无法让它与 DataGrid 一起使用。具体来说,我一直在尝试将此解决方案用于 DataGridTemplateColumn 上的“CellEditingTemplate”的 DataTemplate。我相信这与 Simon_Weaver 指出的问题相同。
  • 我已经从sdk:DataGridRowDetailsTemplate 中的DataTemplate 尝试过这个,但不起作用。有任何想法吗?我想确定DataGrid 当前是否处于编辑模式。
【解决方案2】:

我一直在与类似的问题作斗争。我的包含一个为每个列表项显示的组合框。顶级 DataContext 绑定到我的视图模型 (MVVM),如下所示:

class ViewModel{
    ObservableCollection<ComboboxListItemType> DataForTheComboBoxList;
    ObservableCollection<MyDataType> DataForTheListBox;
    ...
}

由于组合框位于列表框的 ItemTemplate (=DataTemplate) 内,因此每个列表项的 DataContext 都设置为 DataForTheListBox 中的相应项,因此组合框无法再从顶级 DataContext 中看到它所需的 DataForTheComboBoxList。

我的(肮脏、丑陋的)解决方法涉及在列表中的每个项目上设置完整的组合框列表,因此它对该列表项中的 DataContext 可见。

首先,您为列表框数据类型创建一个部分类。 (通常这将来自服务引用,因此您不能直接触摸生成的代码而不会丢失它)。这个部分类包含一个引用组合框列表项类型的新属性:

public partial class MyDataType
{
    private ObservableCollection<ComboboxListItemType> m_AllComboboxItems;
    public ObservableCollection<ComboboxListItemType> AllComboboxItems
    {
        get { return m_AllComboboxItems; }
        set
        {
            if (m_AllComboboxItems != value)
            {
                m_AllComboboxItems = value;
                RaisePropertyChanged("AllComboboxItems");
            }
        }
    }
}

接下来,您必须在 DataForTheListBox 集合中的每个元素上设置此属性

// in ViewModel class
foreach(var x in this.DataForTheListBox)
{
    x.AllComboboxItems = this.DataForTheComboBoxList;
}

然后回到你的 XAML:

<DataTemplate x:Key="ListBoxItemTemplate">
    ...
    <Combobox
        ItemsSource="{Binding AllComboboxItems}"
        SelectedItem="{Binding CurrentBlah}"/>
</DataTemplate>

不要忘记,要让组合框正确显示当前项,选定的项必须引用组合框的 ItemsSource 中的实际项。如果您从具有代表组合框项目的 ID 或对象的 Web 服务获取数据,则必须重新引用它们以指向实际集合。

【讨论】:

    【解决方案3】:

    如果您尝试使用 DataForm 执行此操作,则 Roboblob 显示的相同方法不起作用。

    This question may have some useful information

    【讨论】:

      【解决方案4】:

      使用 silverlight 可以做的非常酷的事情之一是使用 Tag 属性来存储对它所绑定的对象的引用。

      首先,在你的类中,声明一个像这样的属性

      public IMyObject Current 
      {
        get {return this;}
      }
      

      然后在控件中引发事件,您可以获得对该对象的引用

      var fe= (FrameworkElement) sender;
      var src = fe.Tag as IMyObject;
      

      所以现在我有了对象,一个对象引用它的父对象是合理的,所以你绑定到

      Current.Parent.QuestionType
      

      【讨论】:

        猜你喜欢
        • 2014-12-02
        • 2013-04-08
        • 1970-01-01
        • 1970-01-01
        • 2015-05-06
        • 2015-07-29
        • 1970-01-01
        • 2013-08-31
        • 1970-01-01
        相关资源
        最近更新 更多