gpt4 book ai didi

c# - 折叠所有扩展器并默认展开其中一个

转载 作者:太空狗 更新时间:2023-10-29 21:34:01 25 4
gpt4 key购买 nike

我有多个扩展器,我一直在寻找一种方法,当其中一个扩展器展开时折叠所有其他扩展器。我找到了这个解决方案 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, 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);

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

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

View 模型:

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 属性中,但默认情况下没有展开器展开!

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

最佳答案

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

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

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

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

要使 ConvertBack 正确,它需要知道其他扩展器:它应该只返回 null 如果它们都是 all崩溃了。不过,我没有看到从转换器内部处理这个问题的干净方法。也许最好的解决方案是使用单向绑定(bind)(无 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对于 View 模型中使用的标识符。

编辑:

为了以更“MVVM”的方式解决它,您可以为每个扩展器创建一个 View 模型集合,并使用一个单独的属性将 IsExpanded 绑定(bind)到:

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;
}
}
}
}

然后将每个扩展器绑定(bind)到 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;

关于c# - 折叠所有扩展器并默认展开其中一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21303697/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com