如果 ONE 展开,则多个 Expander 必须折叠

Posted

技术标签:

【中文标题】如果 ONE 展开,则多个 Expander 必须折叠【英文标题】:Multiple Expander have to collapse if ONE is expanded 【发布时间】:2011-05-25 20:11:48 【问题描述】:

有 4 个扩展器控件。当一个扩展器展开时,如何让所有其他扩展器折叠/关闭?

【问题讨论】:

【参考方案1】:

试试下面的代码:

XAML:

        <StackPanel Name="StackPanel1">
            <StackPanel.Resources>
                <local:ExpanderToBooleanConverter x:Key="ExpanderToBooleanConverter" />
            </StackPanel.Resources>
            <Expander Header="Expander 1"
                      IsExpanded="Binding SelectedExpander, Mode=TwoWay, Converter=StaticResource ExpanderToBooleanConverter, ConverterParameter=1">
                <TextBlock>Expander 1</TextBlock>
            </Expander>
            <Expander Header="Expander 2"
                      IsExpanded="Binding SelectedExpander, Mode=TwoWay, Converter=StaticResource ExpanderToBooleanConverter, ConverterParameter=2">
                <TextBlock>Expander 2</TextBlock>
            </Expander>
            <Expander Header="Expander 3"
                      IsExpanded="Binding SelectedExpander, Mode=TwoWay, Converter=StaticResource ExpanderToBooleanConverter, ConverterParameter=3">
                <TextBlock>Expander 3</TextBlock>
            </Expander>
            <Expander Header="Expander 4"
                      IsExpanded="Binding SelectedExpander, Mode=TwoWay, Converter=StaticResource ExpanderToBooleanConverter, ConverterParameter=4">
                <TextBlock>Expander 4</TextBlock>
            </Expander>
        </StackPanel>

转换器:

public class ExpanderToBooleanConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        return (value == parameter);
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (System.Convert.ToBoolean(value)) return parameter;
        return null;
    

视图模型:

public class ExpanderListViewModel

    public Object SelectedExpander  get; set; 

初始化

StackPanel1.DataContext = new ExpanderListViewModel();

说明:

在 XAML 中,我们有 4 个扩展器。它们都从容器StackPanelDataContext 继承了ViewModelExpanderListViewModel 类型)。

它们都绑定到 ViewModel 类的单个属性。并在绑定中使用ConverterParameter 为自己定义了一个唯一索引。每当您展开扩展器时,该索引都会保存在 SelectedExpander 属性中。使用该索引,如果存储索引与给定索引匹配,Converter 返回true,如果存储索引不匹配,则返回false

Converter 类的ConvertConvertBack 方法中放置一个断点,你会看到发生了什么。

【讨论】:

@Lisa:如果你说的是Silverlight Toolkit,它正式属于future Silverlight。它由来自Microsoft 的人员维护,添加到其中的控件将添加到Silverlight 的未来版本中。所以,你没有理由不使用它。 我发现这个解决方案非常有用。谢谢 如何在应用程序启动时展开“Expander 1”? 调试时,我注意到当我为所有扩展器输入相同的ConverterParameter 时,我仍然可以工作(一次只打开一个扩展器)。但是,当我扩展一个时,难道不应该扩展所有这些吗?在转换器的Convert 方法中设置断点后,似乎value == parameter 的表达式始终为假,即使保持相同的值......对此有何解释? 经过一番研究,我发现当用==运算符比较对象时,它实际上比较的是引用而不是对象的内容。因此,为了使代码按预期工作,您应该在比较之前将valueparameter 转换为整数。因此,Convert 方法的 return 语句应该是 return (System.Convert.ToInt32(value) == System.Convert.ToInt32(parameter));【参考方案2】:

我就是这样做的:

1) 添加了一个 StackPanel 并且必须添加一个名称标签属性(因为这是主节点)。

StackPanel Name="StackPanel1"

2) 根据需要添加任意数量的扩展器(如果需要,可以添加 1 到 100 个),每个扩展器必须具有:-

Expanded="Expander_Expanded"

添加(注意所有的措辞都 100% 相同)。

3) 没有其他细节需要匹配每个(不需要高度的名称等)。

Xaml:

<StackPanel Name="StackPanel1">
<Expander Header="Expander 1" Expanded="Expander_Expanded">
    <TextBlock>Expander 1</TextBlock>
</Expander>
<Expander Header="Expander 2" Expanded="Expander_Expanded">
    <TextBlock>Expander 2</TextBlock>
</Expander>
<Expander Header="Expander 3" Expanded="Expander_Expanded" >
    <TextBlock>Expander 3</TextBlock>
</Expander>
<Expander Header="Expander 4" Expanded="Expander_Expanded" >
    <TextBlock>Expander 4</TextBlock>
</Expander>

4) 要控制名为“StackPanel1”StackPanel 上所有“Expanders”的打开/关闭,您只需添加以下代码一次。

VB 代码隐藏:

Private Sub Expander_Expanded(sender As Object, e As RoutedEventArgs)
    For Each exp As Expander In StackPanel1.Children
        If exp IsNot sender Then
            exp.IsExpanded = False
        End If
    Next
End Sub

5)现在您可以更改/添加什么内容、按钮、文本框等。您只需要不更改 2 件事 1、“StackPanel 名称”2、“Expander Expanded”而不更新代码隐藏,否则不会工作。

希望这些信息对您有所帮助。

发生了什么事?

1) 所有面板都是父面板,该面板上的所有控件都是子面板,

2) 所有控件都是父面板的子控件。

3) 一个类一次处理一个调用。

4) 类处理孩子。

6) 班级移动到下一个孩子。

7) 询问完所有孩子后停止。

所以伪代码是这样的:

1) 听一个孩子的名字 x

2) 询问父母孩子列表中的每个孩子

3) 如果孩子没有打电话,那么

4) 子级扩展为假

5) 结束询问那个孩子

6) 移动到下一个孩子并再次询问

7) 直到所有孩子都被问到

【讨论】:

您可能想解释一下是什么让这个答案正确。【参考方案3】:

设置丢失的焦点似乎是最简单的方法。

Xaml:

<Expander LostFocus="CollapseExpander" ExpandDirection="Down" Width="175">
    <ListBox Height="265" Margin="0,5,0,10">
    </ListBox>
</Expander>

VB:

Private Sub CollapseExpander(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)

 sender.IsExpanded = False

End Sub

【讨论】:

该解决方案的缺点是,当您单击用户控件/窗口中的任何其他位置时,扩展器也会失去焦点并折叠扩展器。【参考方案4】:

使用 MVVM 并将 IsExpanded 属性绑定到视图模型上的布尔标志。当一个更新为true时,将所有其他设置为false

【讨论】:

控制逻辑应该在视图模型中吗? 除了控制视图之外,视图模型还有什么用途?只要您可以在不需要实例化任何视图对象的情况下实例化和测试视图模型,我就称解耦成功。【参考方案5】:

@wassim-azirar 询问接受的答案:

如何在应用程序启动时展开“扩展器 1”?

我在 ViewModel 中添加了:

SelectedExpander = "1";

因为“1”与 XAML 中的“1”不是同一个对象,所以这不起作用,所以我改变了 decyclone 的答案,如下所示:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

    return (string)value == (string)parameter;

decyclone 的回答对我很有帮助 - 谢谢。 因此,如果有人需要,我想分享我的经验。

【讨论】:

【参考方案6】:

试试 WPF Toolkit - February 2010 Release 的 Accordion 控件

http://www.dotnetspark.com/kb/1931-accordion-wpf-toolkit-tutorial.aspx

示例代码:

<my:Accordion  x:Name="accordion1" VerticalAlignment="Top" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" SelectionMode="ZeroOrOne">
        <my:AccordionItem Header="First Header" Content="First Content"/>
        <my:AccordionItem Header="Second Header">
            <StackPanel Height="300">
            <TextBlock Text="Second Content" /></StackPanel>
        </my:AccordionItem>
        <my:AccordionItem>
            <my:AccordionItem.Header>
                <TextBox Text="Third Item" />
            </my:AccordionItem.Header>
            <StackPanel Height="300">
                <TextBlock Text="Third Item" />
            </StackPanel>
        </my:AccordionItem>
        <my:AccordionItem>
            <my:AccordionItem.Header>
                <TextBlock Text="Fourth Item" />
            </my:AccordionItem.Header>
            <StackPanel Height="300">
                <TextBlock Text="Third Item" />
            </StackPanel>
        </my:AccordionItem>
    </my:Accordion>

【讨论】:

这个组件太可怕了,有几个错误、缺陷和问题。有没有其他提出相同操作的?【参考方案7】:

我也需要这个,但 IMO 的所有答案都太过分了。 这是我的做法:

    添加了 StackPanel(子对齐设置为垂直)。 在其中添加了 3 个扩展器。 (需要 3 个) 将扩展器的高度设置为 120 像素以向其中添加元素。 每个扩展器都称为 ex1..3。

    每个人有 2 个事件

    private void ex1_Collapsed(object sender, RoutedEventArgs e)  
      
        ex1.Height = 23.0;  
      
    
    private void ex1_Expanded(object sender, RoutedEventArgs e)    
      
        ex1.Height = 120.0;  
        ex2.IsExpanded = false;  
        ex3.IsExpanded = false;  
      
    
    在 window_loaded 处将所有应折叠的扩展器高度重置为 23 像素。

它。

【讨论】:

以上是关于如果 ONE 展开,则多个 Expander 必须折叠的主要内容,如果未能解决你的问题,请参考以下文章

wpf 列表菜单 收起与展开,通过Grid DoubleAnimation或者Expander实现

2021-08-19 WPF控件专题 Expander 控件详解

【WPF】Expander只展示一个

WPF实现QQ群文件列表动画

如果模态关闭并重新打开或验证捕获丢失的输入,则使用 .one 提交的模态表单提交多个

Lodash _.filter 函数必须只满足 ONE 条件