我可以将按钮的可见性绑定到其包含的ItemTemplate的IsSelected属性吗?

时间:2014-06-21 00:42:26

标签: wpf xaml winrt-xaml

我正在开发Windows应用商店应用。一个页面包含一个ListViewStackPanel有一些TextBlocks和三个按钮:

enter image description here

我希望只有在选择了它们所属的ListItem时才能看到这三个按钮。我已经在按钮的Binding属性上尝试了Visibility的所有可能安排,但到目前为止还没有任何工作。似乎WinRT应用程序的受约束的绑定类型集阻止我使用已知的解决方案。有什么我可以做的吗?

我目前正试图从ListView SelectionChanged事件处理程序中的代码中操作对象的角度来考虑它,但还没有任何结果。

以下是ItemTemplate的XAML:

  <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel FlowDirection="LeftToRight" Orientation="Horizontal">
                    <StackPanel Style="{StaticResource SessionBlock}" DoubleTapped="StackPanel_DoubleTapped">
                        <TextBlock Style="{StaticResource SessionTitle}" Text="{Binding Title}" />
                        <TextBlock Style="{StaticResource SessionStepCount}">
                            <Run Text="{Binding StepsCount}" />
                            <Run Text=" Steps" />
                        </TextBlock>
                    </StackPanel>
                    <Button Content="&#xE17E;&#xE102;"
                            Style="{StaticResource ActionButton}" />
                    <Button Content="&#xE17E;&#xE104;"
                            Style="{StaticResource ActionButton}" />
                    <Button Content="&#xE17E;&#xE107;"
                            Style="{StaticResource ActionButton}" />
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>

2 个答案:

答案 0 :(得分:1)

您可以将TemplatedParent用于相同的

首先在资源中声明bool到可见性转换器

例如

    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

然后在xaml中将以下绑定应用于Visibility,并使用上面声明的转换器

    Visibility="{Binding TemplatedParent.IsSelected,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibilityConverter}}"

所以这里的技巧是找到datatemplate的TemplatedParent,它是内容演示者,然后是它的TemplatedParent,它是ListViewItem,IsSelected属性就是你要找的东西

所以你的例子可以如下

    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel FlowDirection="LeftToRight" Orientation="Horizontal">
                <StackPanel Style="{StaticResource SessionBlock}" DoubleTapped="StackPanel_DoubleTapped">
                    <TextBlock Style="{StaticResource SessionTitle}" Text="{Binding Title}" />
                    <TextBlock Style="{StaticResource SessionStepCount}">
                        <Run Text="{Binding StepsCount}" />
                        <Run Text=" Steps" />
                    </TextBlock>
                </StackPanel>
                <Button Content="&#xE17E;&#xE102;"
                        Style="{StaticResource ActionButton}" 
                        Visibility="{Binding TemplatedParent.IsSelected,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibilityConverter}}" />
                <Button Content="&#xE17E;&#xE104;"
                        Style="{StaticResource ActionButton}" 
                        Visibility="{Binding TemplatedParent.IsSelected,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibilityConverter}}" />
                <Button Content="&#xE17E;&#xE107;"
                        Style="{StaticResource ActionButton}" 
                        Visibility="{Binding TemplatedParent.IsSelected,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibilityConverter}}" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>

在上面的示例中,我将相同的内容应用于所有三个按钮,您也可以将它们全部放在堆栈面板中并对其应用单个绑定,从而缩短代码。

答案 1 :(得分:-1)

我从来没有找到过通过XAML做我想做的事情的方法,但我能够用一些代码隐藏来完成它。可悲的是,代码隐藏中的东西真的很模糊,需要一些幸运和勤奋的Google-fu来找到这样做的咒语。真正的归功于此博客页面:http://blogs.msdn.com/b/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx

我做的是,我从该博客页面添加了稍微修改过的代码版本:

private List<childItem> findVisualChildren<childItem>(DependencyObject obj) where childItem : DependencyObject {
    List<childItem> results = new List<childItem>();
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is childItem) {
            results.Add((childItem)child);
        } else {
            results.AddRange(findVisualChildren<childItem>(child));
        }
    }

    return results;
}

它以递归方式搜索可视元素的子元素以查找给定类型的元素,并将它们全部返回到列表中。整洁,但这不是所有看起来像jibber-jabber? Win Forms至少提供了一种与子节点交互的非常明显的方法。

然后,从SelectionChanged的{​​{1}}事件处理程序内部调用该方法:

ListView

因此,您可以看到处理程序迭代ListView中的每个项目。对于每一个,它抓住private void SessionsList_SelectionChanged(object sender, SelectionChangedEventArgs e) { for (int itemIdx = 0; itemIdx < SessionsList.Items.Count; itemIdx++) { ListViewItem eachItem = (ListViewItem)SessionsList.ContainerFromIndex(itemIdx); // Content Presenter stuff is from the blog post. I have no idea. var presenters = findVisualChildren<ContentPresenter>(eachItem); if (presenters != null && presenters.Count > 0) { var buttonsList = findVisualChildren<Button>(presenters[0]); if (buttonsList != null && buttonsList.Count > 0) { for (int buttonIdx = 0; buttonIdx < buttonsList.Count; buttonIdx++) { Button eachButton = (Button)buttonsList[buttonIdx]; if (itemIdx == SessionsList.SelectedIndex) { eachButton.Visibility = Visibility.Visible; } else { eachButton.Visibility = Visibility.Collapsed; } } } } } } 无论是什么。然后,它使用该对象上的ContentPresenter来查找属于它的所有按钮。如果它在当前选定的项目上运行,则按钮可见;否则,它们就会崩溃。

它完全符合我的要求,但我不禁感到失望的是,我找不到正确的约束法术来做'正确的方法'。

我是否正确地认为WinFT版本的WPF严重削弱了绑定能力?它似乎与WPF中可用于我工作的非商店桌面应用程序的内容相差甚远。