Access parent datacontext in listbox in Silverlight
Asked Answered
T

4

24

In Silverlight 2 I'm using a usercontrol which inherits the datacontext of the page that it's embedded on. This datacontext contains question text, a question type and a collection of answers. In the user control is a listbox which is bound to the collection of answers. As shown below:

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

This listbox has an associated style to display the answers in the form of radio buttons or checkboxes (which I would like to hide or show depending on the question type) as:

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

So my question is then: how do you access the parent data context in order to get the QuestionType (as this is a property on the user control datacontext itself, not a property on an AnswerItem in the AnswerList)?

Alternatively is there a better way to switch styles dynamically in the xaml based on a binding value?

Thetis answered 22/12, 2008 at 8:25 Comment(1)
Do you have any way to change your accepted answer? The one below, by Roboblob, is a correct answer. The accepted answer is incorrect for Silverlight and misleading.Bilious
C
55

In Silverlight 3 and higher you can use Element to Element binding and point to the controls DataContext and then some property in my example its Threshold property.

So first name your control (for example in my example its x:Name="control")

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

then inside this control in your ListBox ItemTemplate you can access parent DataContext like this:

    <ListBox ItemsSource="{Binding Path=SomeItems}" >
        <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding ElementName=control, Path=DataContext.Threshold}"/>
            </StackPanel>
        </DataTemplate>
       </ListBox.ItemTemplate>         
       </ListBox>
Coelacanth answered 11/1, 2010 at 8:52 Comment(5)
important not to miss that you need to explicitly put in 'DataContext'. i had previously abandoned an attempt to do this because i managed to forget to put 'DataContext'Tessitura
@roboblob - do you happen to know a good way to do this within a DataForm (doesn't work in same way as shown in my post below)Tessitura
@Coelacanth - Clever solution to a common problem. I will go down-vote the one marked as "the" answer as it is misleading and actually wasted our time until we saw yours.Bilious
This solution looks very elegant, but unfortunately I haven't been able to get it working with a DataGrid. Specifically I've been trying to use this solution for a DataTemplate for the "CellEditingTemplate" on a DataGridTemplateColumn. I believe it is the same problem that Simon_Weaver is pointing out.Mcquiston
I've tried this from a DataTemplate in sdk:DataGrid's RowDetailsTemplate and doesn't work. Any ideas? I want to determine if the DataGrid is currently in edit mode.Plano
K
1

I've just been battling with a similar problem. Mine consists of a combobox that displays for each listitem. The top-level DataContext is bound to my viewmodel (MVVM) and looks like this:

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

Because the combobox is within the ItemTemplate (=DataTemplate) for the listbox, the DataContext for each list item is set to the appropriate item in DataForTheListBox, the combobox can no longer see the DataForTheComboBoxList it needs from the top-level DataContext.

My (dirty, ugly) workaround involves setting the complete combobox list on each item in the list, so it becomes visible to the DataContext in this list item.

First you make a partial class for your listbox data type. (Generally this will be coming from a service reference, so you cant touch the generated code directly without potentially losing it). This partial class contains a new property referring to your combobox list item type:

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");
            }
        }
    }
}

Next you have to set this property on each element in the DataForTheListBox collection

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

Then back in your XAML:

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

Dont forget that for the combobox to correctly display the current item, the selected item must refer to the actual item in the combobox's ItemsSource. If you are getting data from a webservice that has IDs or objects to represent the item for the combobox, you must re-reference them to point to the actual collection.

Keeshakeeshond answered 4/2, 2009 at 3:20 Comment(0)
N
1

On of the very cool things you can do with silverlight is to use the Tag attribute to store a reference to the object to which it is bound.

First, in your class, declare a property like this

public IMyObject Current 
{
  get {return this;}
}

Then on the control raising the event in you can get a reference to the object

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

So now that I have the object, it's reasonable for an object to have reference to its parent so then you bind to

Current.Parent.QuestionType
Nebiim answered 20/3, 2009 at 0:21 Comment(0)
T
1

If you're trying to do this with a DataForm he same method shown by Roboblob doesn't work.

This question may have some useful information

Tessitura answered 19/7, 2010 at 1:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.