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. 当然,这不是正确的行为.所以解决方案依赖于源永远不会被更新,除非用户实际切换扩展器. 因此,我怀疑问题是控件的初始化以某种方式触发源更新.即使扩展器1被正确初始化为扩展,当在任何其他扩展器上刷新绑定时,它也会被重置. 要使ConvertBack正确,它需要知道其他扩展器:如果所有扩展器都折叠,它应该只返回null.但是,我没有看到从转换器中处理这个问题的干净方法.也许最好的解决方案是使用单向绑定(无ConvertBack)并以这种方式或类似方式处理Expanded和Collapsed事件(其中_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; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |