WP8 ListBox中的FindAncestor实现

时间:2014-06-06 11:53:42

标签: windows-phone-8 listbox findancestor

我想直接实现一个Listbox绑定,这里是我在WPF语法中使用的代码

<ListBox  Name="lboxData" ItemsSource="{Binding}">
<ListBox.ItemTemplate >
    <DataTemplate>
        <StackPanel>                        
            <ToggleButton x:Name="toggleChild"  Style="{StaticResource ChapterHeadingStyle}"
                  IsChecked="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"   // This is what i have to change . I want to set it based on the status of the ListBoxItem & Given code is the one i used in WPF app 
            />
            <ListBox Visibility="{Binding IsChecked, ElementName=toggleChild, Converter={StaticResource boolToVis}}" ItemsSource="{Binding pages}" Margin="10,0,0,0"  >
                        <ListBox.ItemTemplate >
                            <DataTemplate>
                              //here is displaying child items one by one ..
                            </DataTemplate>
                        </ListBox.ItemTemplate >
            </ListBox>
         </ListBox.ItemTemplate >
    </DataTemplate>
</StackPanel>       
</ListBox>

问题是在WP8中 RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = {x:Type ListBoxItem} 不受支持。那么我怎么能在WP8中实现同样的功能呢。我想将切换按钮设置为Checked是否选中了容器ListboxItem,否则我想将IsChecked设置为False。

1 个答案:

答案 0 :(得分:1)

我将首先编写一个比较器类

public  class ElementComparer : FrameworkElement
{
    public object Element1
    {
        get { return (object)GetValue(Element1Property); }
        set { SetValue(Element1Property, value); }
    }

    // Using a DependencyProperty as the backing store for Element1.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty Element1Property =
        DependencyProperty.Register("Element1", typeof(object), typeof(ElementComparer), new PropertyMetadata(null, UpdateResult));

    public object Element2
    {
        get { return (object)GetValue(Element2Property); }
        set { SetValue(Element2Property, value); }
    }

    // Using a DependencyProperty as the backing store for Element2.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty Element2Property =
        DependencyProperty.Register("Element2", typeof(object), typeof(ElementComparer), new PropertyMetadata(null, UpdateResult));

    public bool Result
    {
        get { return (bool)GetValue(ResultProperty); }
        set { SetValue(ResultProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Result.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ResultProperty =
        DependencyProperty.Register("Result", typeof(bool), typeof(ElementComparer), new PropertyMetadata(false, OnResultChanged)); //added changed handler

    private static void OnResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ElementComparer ec = d as ElementComparer;
        //if true then set the element 2 to element 1 of the comparer otherwise null
        ec.Element2 = ((bool)e.NewValue) ? ec.Element1 : null;
    }

    private static void UpdateResult(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ElementComparer ec = d as ElementComparer;
        ec.Result = object.ReferenceEquals(ec.Element1, ec.Element2);
    }
}

然后我将Isggcked从togglebutton绑定到ElementComparer的Result,并将comaprer的Element1和Element2与当前项和lboxData的SelectedItem绑定(ListBox)

<ListBox Name="lboxData" ItemsSource="{Binding}">
    <ListBox.ItemTemplate >
        <DataTemplate>
            <StackPanel>
                <!--added  Mode=TwoWay to binding of Element2-->
                <local:ElementComparer x:Name="ElementComparer"
                                    Element1="{Binding}"
                                    Element2="{Binding SelectedItem, ElementName=bookTOCBox, Mode=TwoWay}" />
                <!--removed Mode=OneWay from binding of IsChecked and added Mode=TwoWay-->
                <ToggleButton x:Name="toggleChild" Content="{Binding name}" 
                              Style="{StaticResource ChapterHeadingStyle}" 
                              IsChecked="{Binding Result, ElementName=ElementComparer, Mode=TwoWay}"/>
                ...
            </StackPanel>

诀窍是将列表的选定项目与当前项目进行比较,以检测是否选中它,只要父列表框的名称为"lboxData",这也将在WP8中起作用

更新摘要

  • 从Toggle的IsChecked属性中删除单向绑定到ElementComparer的结果
  • 添加了对SelectedItem的双向绑定到ElementComparer的Element2
  • 为ElementComparer
  • 中的Result属性添加了属性更改处理程序
  • 当结果发生变化且为真(检查切换)时,将Element1的值推送到Element2
  • 由于Element2绑定到SelectedItem,它会强制其他项的结果为false,因此关闭切换并折叠子列表
  • 将to Mode = TwoWay添加到切换的IsChecked属性,因为似乎退出不可预测而没有它

<强>附加功能

另外如果您不希望在列表项中看到丑陋的蓝色选择,那么您也可以将以下内容添加到您的资源中

<Style TargetType="ListBoxItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border Background="Transparent">
                    <ContentPresenter/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>