微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 默认情况下折叠所有展开器并展开其中一个

我有多个扩展器,我正在寻找一种方法来折叠所有其他扩展器,当其中一个扩展时.我发现这个解决方here

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,ConverterParameter=2}">
        <TextBlock>Expander 2</TextBlock>
    </Expander>
    <Expander Header="Expander 3"
        IsExpanded="{Binding SelectedExpander,ConverterParameter=3}">
        <TextBlock>Expander 3</TextBlock>
    </Expander>
    <Expander Header="Expander 4"
        IsExpanded="{Binding SelectedExpander,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);

        // I tried thoses too :
        return value != null && (value.ToString() == parameter.ToString());
        return value != null && (value.ToString().Equals(parameter.ToString()));
    }

    public object ConvertBack(object value,CultureInfo culture)
    {
        return System.Convert.ToBoolean(value) ? parameter : null;
    }
}

视图模型:

public class ExpanderListviewmodel : INotifyPropertyChanged
{
    private Object _selectedExpander;

    public Object SelectedExpander
    {
        get { return _selectedExpander; } 
        set
        {
            if (_selectedExpander == value)
            {
                return;
            }

            _selectedExpander = value;
            OnPropertyChanged("SelectedExpander");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this,new PropertyChangedEventArgs(propertyName));
        }
    }
}

初始化

var viewmodel = new ExpanderListviewmodel();
StackPanel1.DataContext = viewmodel;
viewmodel.SelectedExpander = 1;

// I tried this also
viewmodel.SelectedExpander = "1";

它工作正常,但现在我想在应用程序启动时扩展其中一个扩展器!

我已经尝试将值(1,2或3)放在SelectedExpander属性中,但认情况下没有扩展器扩展!

如何将这种可能性添加到我的扩展器中?

解决方法

考虑如果在扩展器2上调用 UpdateSource而选择扩展器1时会发生什么:

>为Expander 2调用ConvertBack及其当前的IsExpanded值(false),并返回null.
> SelectedExpander更新为null.
>为所有其他扩展器调用Convert,因为SelectedExpander已更改,导致所有其他IsExpanded值也设置为false.

当然,这不是正确的行为.所以解决方案依赖于源永远不会被更新,除非用户实际切换扩展器.

因此,我怀疑问题是控件的初始化以某种方式触发源更新.即使扩展器1被正确初始化为扩展,当在任何其他扩展器上刷新绑定时,它也会被重置.

要使ConvertBack正确,它需要知道其他扩展器:如果所有扩展器都折叠,它应该只返回null.但是,我没有看到从转换器中处理这个问题的干净方法.也许最好的解决方案是使用单向绑定(无ConvertBack)并以这种方式或类似方式处理ExpandedCollapsed事件(其中_expanders是所有扩展器控件的列表):

private void OnExpanderIsExpandedChanged(object sender,RoutedEventArgs e) {
    var selectedExpander = _expanders.FirstOrDefault(e => e.IsExpanded);
    if (selectedExpander == null) {
        viewmodel.SelectedExpander = null;
    } else {
        viewmodel.SelectedExpander = selectedExpander.Tag;
    }
}

在这种情况下,我使用Tag作为viewmodel中使用的标识符.

编辑:

要以更“MVVM”的方式解决它,您可以为每个扩展器提供一组视图模型,并使用单独的属性将IsExpanded绑定到:

public class Expanderviewmodel {
    public bool IsSelected { get; set; }
    // todo INotifyPropertyChanged etc.
}

将集合存储在ExpanderListviewmodel中,并在初始化时为每个集合添加PropertyChanged处理程序:

// in ExpanderListviewmodel
foreach (var expanderviewmodel in Expanders) {
    expanderviewmodel.PropertyChanged += Expander_PropertyChanged;
}

...

private void Expander_PropertyChanged(object sender,PropertyChangedEventArgs e) {
    var thisExpander = (Expanderviewmodel)sender;
    if (e.PropertyName == "IsSelected") {
        if (thisExpander.IsSelected) {
            foreach (var otherExpander in Expanders.Except(new[] {thisExpander})) {
                otherExpander.IsSelected = false;
            }
        }
    }
}

然后将每个扩展器绑定到Expanders集合的不同项:

<Expander Header="Expander 1" IsExpanded="{Binding Expanders[0].IsSelected}">
    <TextBlock>Expander 1</TextBlock>
</Expander>
<Expander Header="Expander 2" IsExpanded="{Binding Expanders[1].IsSelected}">
    <TextBlock>Expander 2</TextBlock>
</Expander>

(您可能还需要研究定义自定义ItemsControl以根据集合动态生成扩展器.)

在这种情况下,将不再需要SelectedExpander属性,但可以通过以下方式实现:

private Expanderviewmodel _selectedExpander;
public Expanderviewmodel SelectedExpander
{
    get { return _selectedExpander; } 
    set
    {
        if (_selectedExpander == value)
        {
            return;
        }

        // deselect old expander
        if (_selectedExpander != null) {
           _selectedExpander.IsSelected = false;
        }

        _selectedExpander = value;

        // select new expander
        if (_selectedExpander != null) {
            _selectedExpander.IsSelected = true;
        }

        OnPropertyChanged("SelectedExpander");
    }
}

并将以上PropertyChanged处理程序更新为:

if (thisExpander.IsSelected) {
    ...
    SelectedExpander = thisExpander;
} else {
    SelectedExpander = null;
}

所以现在这两行是初始化第一个扩展器的等效方法

viewmodel.SelectedExpander = viewmodel.Expanders[0];
viewmodel.Expanders[0].IsSelected = true;

原文地址:https://www.jb51.cc/csharp/244677.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐