web-dev-qa-db-ja.com

Silverlightのリストボックスで親データコンテキストにアクセスする

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でスタイルを動的に切り替えるより良い方法はありますか?

24
James_2195

Silverlight 3以降では、要素間のバインディングを使用して、コントロールの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>
55
Roboblob

データフォームを使用してこれを実行しようとしている場合、RoboBlobで示されているのと同じ方法は機能しません。

この質問にはいくつかの有用な情報があるかもしれません

1
Simon_Weaver

Silverlightで実行できる非常に優れた機能の1つは、Tag属性を使用して、バインド先のオブジェクトへの参照を格納することです。

まず、クラスで、次のようなプロパティを宣言します

public IMyObject Current 
{
  get {return this;}
}

次に、イベントを発生させるコントロールで、オブジェクトへの参照を取得できます

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

これでオブジェクトができたので、オブジェクトがその親を参照するのは合理的であるため、にバインドします。

Current.Parent.QuestionType
1
Doug

私はちょうど同様の問題と戦っています。鉱山は、リストアイテムごとに表示されるコンボボックスで構成されています。トップレベルの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のactualアイテムを参照している必要があることを忘れないでください。コンボボックスのアイテムを表すIDまたはオブジェクトを持つWebサービスからデータを取得する場合は、実際のコレクションを指すようにそれらを再参照する必要があります。

1
geofftnz