我将从编写一个比较器类开始
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);
}
}
然后我将 IsChecked 从 togglebutton 绑定到 ElementComparer 的 Result,并将comaprer 的 Element1 和 Element2 与当前项和 lboxData (ListBox) 的 SelectedItem 绑定
<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中也可以工作
更新摘要
- 从切换的 IsChecked 属性中删除了一种方式绑定到 ElementComparer 的结果
- 将 SelectedItem 添加到 ElementComparer 的 Element2 的两种方式
- 为 ElementComparer 中的 Result 属性添加了属性更改处理程序
- 当结果发生变化并且为真时(选中切换)将 Element1 的值推送到 Element2
- 由于 Element2 绑定到 SelectedItem,它会强制其他项目的结果为 false,因此关闭切换并折叠子列表
- 将 Mode=TwoWay 添加到 toggle 的 IsChecked 属性,因为没有它似乎就无法预测
附加功能
此外,如果您不想在列表项中看到难看的蓝色选择,那么您也可以将以下内容添加到您的资源中
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Background="Transparent">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>