Подтвердить что ты не робот

Доступ к родительскому datacontext в списке в Silverlight

В Silverlight 2 я использую usercontrol, который наследует datacontext страницы, на которой он встроен. Этот файл данных содержит текст вопроса, тип вопроса и набор ответов. В пользовательском элементе управления находится список, связанный с набором ответов. Как показано ниже:

<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 (поскольку это свойство в самом пользовательском элементе управления datacontext, а не в свойстве AnswerItem в ListList)?

Альтернативно существует ли лучший способ динамического переключения стилей в xaml на основе значения привязки?

4b9b3361

Ответ 1

В Silverlight 3 и выше вы можете использовать привязку Element to Element и указывать на элементы управления DataContext, а затем некоторое свойство в моем примере его свойство Threshold.

Итак, сначала назовите свой контроль (например, в моем примере его x: Name= "control" )

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

то внутри этого элемента управления в элементе ItemBox ListBox вы можете получить доступ к родительскому 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>

Ответ 2

Я только что сражался с подобной проблемой. Mine состоит из выпадающего списка, которое отображается для каждого списка. Верхний уровень DataContext связан с моей моделью просмотра (MVVM) и выглядит следующим образом:

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

Поскольку combobox находится внутри ItemTemplate (= DataTemplate) для списка, DataContext для каждого элемента списка устанавливается в соответствующий элемент в DataForTheListBox, combobox больше не может видеть DataForTheComboBoxList, который ему нужен, из DataContext верхнего уровня.

Мое (грязное, уродливое) обходное решение включает настройку полного списка списков списков для каждого элемента в списке, поэтому он становится видимым для 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>

Не забывайте, что для корректного отображения текущего элемента в поле со списком выбранный элемент должен ссылаться на фактический элемент в элементе Items_SourceBox. Если вы получаете данные из веб-службы, у которой есть идентификаторы или объекты для представления элемента для combobox, вы должны повторно ссылаться на них, чтобы указать на фактическую коллекцию.

Ответ 3

Из самых интересных вещей, которые вы можете сделать с помощью silverlight, является использование атрибута Tag для хранения ссылки на объект, к которому он привязан.

Во-первых, в вашем классе объявите свойство, подобное этому

public IMyObject Current 
{
  get {return this;}
}

Затем на элементе управления, поднимающем событие, вы можете получить ссылку на объект

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

Итак, теперь, когда у меня есть объект, разумно, чтобы объект имел ссылку на его родительский объект, поэтому вы привязываетесь к

Current.Parent.QuestionType