我有多个扩展器,并且我一直在寻找一种方法,当其中一个扩展器扩展时,将所有其他扩展器折叠起来。我在这里找到了这个解决方案
<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;
}
}
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属性中,但是默认情况下,没有任何扩展器可以扩展!
如何将这种可能性添加到我的扩展器中?
考虑如果在选择扩展器1时在扩展器2上调用UpdateSource会发生什么情况:
ConvertBack
会以当前IsExpanded
值(false
)为扩展器2调用,并返回null
。SelectedExpander
已更新为null
。Convert
对于所有其他扩展器,都会调用,因为它已SelectedExpander
更改,导致所有其他IsExpanded
值也都设置false
为。当然,这不是正确的行为。因此,解决方案取决于源永远不会更新,除非用户实际切换了扩展器。
因此,我怀疑问题在于控件的初始化以某种方式触发了源代码更新。即使将扩展器1正确初始化为扩展,当在其他任何扩展器上刷新绑定时,它也会被重置。
为了ConvertBack
正确起见,它需要注意其他扩展器:仅null
当所有扩展器都折叠时才返回。但是,我看不到从转换器内部处理此问题的干净方法。也许最好的解决方案是使用单向绑定(no 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作为在视图模型中使用的标识符。
编辑:
为了以更“ 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,以便根据该集合动态生成Expanders。)
在这种情况下,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;
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句