本文介绍了GroupStyle和Expander:在数据模型中保存IsExpanded状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 您好! 我正在做一些研究,但我无法找到问题的解决方案。 I有一个具有此属性的ViewModel public ICollectionView Inputs { get { m_CollectionViewSource.Source = m_InputsCollection; m_ICollectionView = m_CollectionViewSource.View; m_ICollectionView.GroupDescriptions.Add(new PropertyGroupDescription(" GroupingCategoryName")); m_ICollectionView.GroupDescriptions.Add(new PropertyGroupDescription(" SubGroupingCategoryName")); 返回m_ICollectionView; } } } m_InputsCollection是具有属性"IsExpanded" $ b的视图模型的ObservableCollection $ b m_ICollectionView的类型为ICollectionView m_CollectionViewSource的类型为CollectionViewSource 我有一个UserControl,我将其绑定到输入< Grid DataContext =" {绑定路径=输入}"> <! - 有效内容的页面右侧 - > < Grid> < ScrollViewer> < ContentControl Content =" {Binding Path = Inputs}" ContentTemplate =" {StaticResource InputsTemplate}" /> < / ScrollViewer> < / Grid> < / Grid> 然后我在ResourceDictionary中拥有所有样式和模板: 1)模板父容器 < DataTemplate x:Key =" InputsTemplate" X:名称= QUOT; InputsTemplate"> < Grid> < ItemsControl ItemsSource =" {Binding}" ItemTemplate =" {StaticResource ViewModelChildTemplate}"> < ItemsControl.GroupStyle> < GroupStyle ContainerStyle =" {StaticResource ContainerStyle}" /> < /ItemsControl.GroupStyle> < / ItemsControl> < / Grid> < / DataTemplate> 2)团体风格:< ;样式x:Key =" ContainerStyle" TargetType =" {x:Type GroupItem}"> < Setter Property =" Template"> < Setter.Value> < ControlTemplate> < Expander Header =" {Binding Name}" IsExpanded =" {Binding Items [0] .IsExpanded,diag:PresentationTraceSources.TraceLevel = High}"> < ItemsPresenter /> < / Expander> < / ControlTemplate> < /Setter.Value> < / Setter> < / Style> 3)扩展器的样式: < Style TargetType =" {x:Type Expander}"> < Setter Property =" Template"> < Setter.Value> < ControlTemplate TargetType =" {x:Type Expander}"> <! - 包含扩展器和要扩展的内容的网格 - > < Grid> < Grid.RowDefinitions> < RowDefinition Height =" {StaticResource ExpanderRowHeight}" /> < RowDefinition x:Name =" ContentRow"高度= QUOT; 0" /> < /Grid.RowDefinitions> <! - 标题组的边框 - > < Border x:Name =" Border" Grid.Row =" 0" BorderThickness =" 1" Margin =" {StaticResource HeaderGroupMargin}" CornerRadius =" 2,2,0,0"> < Grid> <! - 切换按钮扩展器 - > < Grid.ColumnDefinitions> < ColumnDefinition Width =" *" /> < /Grid.ColumnDefinitions> < ToggleButton VerticalAlignment =" Center" HorizontalAlignment =" Stretch" HorizontalContentAlignment =" Stretch" Margin =" {StaticResource HeaderToggleButtonMargin}" OverridesDefaultStyle =" True" Template =" {StaticResource ExpanderToggleButton}" IsChecked =" {Binding IsExpanded,Mode = TwoWay, RelativeSource = {RelativeSource TemplatedParent}}"> < ToggleButton.Background> < LinearGradientBrush EndPoint =" 0.5,1" StartPoint可以= QUOT; 0.5,0"> < GradientStop Color =" {DynamicResource ControlLightColor}"偏移量=" 0" /> < GradientStop Color =" {DynamicResource ControlMediumColor}"偏移量=" 1 QUOT; /> < / LinearGradientBrush> < /ToggleButton.Background> < / ToggleButton> < / Grid> < / Border> <! - 内容的边框(孩子们) - > < Border x:Name =" Content" Grid.Row =" 1" BorderThickness =" 1,0,1,1" CornerRadius =" 0,0,2,2"> < ContentPresenter Margin =" 4" /> < / Border> < / Grid> < ControlTemplate.Triggers> < Trigger Property =" IsExpanded"值= QUOT;真"> < Setter TargetName =" ContentRow" Property =" Height" Value =" {Binding Height,ElementName = Content}" /> < / Trigger> < /ControlTemplate.Triggers> < / ControlTemplate> < /Setter.Value> < / Setter> < / Style> 我的结果是两个级别的分组: 我现在唯一的问题是保留扩展器的状态。 正如我所说,m_InputsCollection是一个ObservableCollection的视图模型 有一个属性"IsExpanded"& 如果我将扩展器绑定到Items [0] .IsExpanded我可以看到(通过启用绑定跟踪)绑定适用于子组中的内部项 (即上图中的"过滤器","域"和"高级")但是对于"强制"而言。我收到了绑定错误: BindingExpression路径错误:'object'''CollectionViewGroupInternal'(HashCode = 19753106)'找不到'IsExpanded'属性。 BindingExpression:路径=项[0] .IsExpanded; DataItem ='CollectionViewGroupInternal'(HashCode = 53740895); target元素是'Expander'(Name =''); target属性为'IsExpanded'(类型'Boolean') 我不明白发生了什么:/ 绑定的完整痕迹在这里: https://pastebin.com/raw/TKEXq26a 感谢您的时间。 Gianpaolo 编辑:我知道可能绑定到Items [0] .IsExpanded不正确, 我只是想了解启用跟踪时会发生什么 Tom Waits:)解决方案 Hi gianpaolo72, >>位于子组中(即"过滤器","域","高级")上图)但是对于"力"而言我收到了一个绑定错误: 子组绑定成功的原因是XAML绑定可以找到带有自定义IsExpanded属性的第一个项目在数据上下文中。因此,对于第一个根组的扩展器(在您的情况下为"Force"),它将在第一个子组的数据上下文中找到IsExpanded 属性(在您的情况下为"Filters"),但是,请注意,在其数据上下文中没有此类属性,只有您可以使用的是 Expander.IsExpanded 控制属性。 那么如何解决这个问题?我们可以在MVVM设计模式中使用值转换器。 我写了一个值转换器来遍历所有子项,例如,如果有任何已扩展的子组,当前的扩展器也应该扩展: public class CheckExpandConverter:IValueConverter { private bool calcIsExpandedFromItems(CollectionViewGroup cvg) { var isExp = false; if(cvg!= null&& cvg.Items.Count> 0) { foreach(cvg.Items中的var项目) { if(item是TestClass) { isExp | =(item as TestClass).IsExpanded; } } } 返回isExp; } 公共对象转换(对象值,类型targetType,对象参数,System.Globalization.CultureInfo文化) { if(value是ReadOnlyObservableCollection< Object>) { var isExp = false; var oc =值为ReadOnlyObservableCollection< Object> ;; foreach(var t in oc) { if(t is TestClass) isExp | =(t as TestClass).IsExpanded; if(t是CollectionViewGroup) isExp | = calcIsExpandedFromItems(t as CollectionViewGroup); } return isExp; } 返回false; } 公共对象ConvertBack(对象值,类型targetType,对象参数,System.Globalization.CultureInfo文化) { throw new NotImplementedException(); } } 我们需要更改GroupItem syle,如下所示:< cv:CheckExpandConverter x:Key =" CheckExpandConverter" /> < Style x:Key =" ContainerStyle" TargetType =" {x:Type GroupItem}"> < Setter Property =" Template"> < Setter.Value> < ControlTemplate> < Expander Header =" {Binding Name}" IsExpanded =" {Binding Items,Converter = {StaticResource CheckExpandConverter},Mode = OneWay}"> < ItemsPresenter /> < / Expander> < / ControlTemplate> < /Setter.Value> < / Setter> < / Style> 屏幕截图: 这是我的模特: public class TestClass { public string Name {get;组; } public bool IsExpanded {get;组; } public string GroupingCategoryName {get;组; } 公共字符串SubGroupingCategoryName {get;组; } } 测试集合: m_InputsCollection = new ObservableCollection< TestClass>(){ new TestClass(){Name =" Items1",IsExpanded = true,GroupingCategoryName =" G1",SubGroupingCategoryName =" G1-S1"}, new TestClass (){Name =" Items2",IsExpanded = false,GroupingCategoryName =" G1",SubGroupingCategoryName =" G1-S1"}, new TestClass(){Name =" Items3",IsExpanded = false ,GroupingCategoryName =" G1",SubGroupingCategoryName =" G1-S2"}, new TestClass(){Name =" Items4",IsExpanded = false,GroupingCategoryName =" G1",SubGroupingCategoryName =" G1 -S2"}, new TestClass(){Name =" Items5",IsExpanded = false,GroupingCategoryName =" G2",SubGroupingCategoryName =" G2-S1"},new TestClass(){Name =" Items6",IsExpanded = false,GroupingCategoryName =" G2",SubGroupingCategoryName =" G2-S1"}, new TestClass(){Name =" Items7",IsExpanded = true,GroupingCategoryName =" G2",SubGroupingCategoryName =" G2-S2"}, new TestClass(){Name =" Items8",IsExpanded = false,GroupingCategoryName =" G2",SubGroupingCategoryName =" ; G2-S2"}, new TestClass(){Name =" Items9",IsExpanded = false,GroupingCategoryName =" G3",SubGroupingCategoryName =" G3-S1"}, new TestClass(){Name =" Items10",IsExpanded = false,GroupingCategoryName =" G3",SubGroupingCategoryName =" G3-S1"}, new TestClass(){Name =" Items11" ,IsExpanded = true,GroupingCategoryName =" G3",SubGroupingCategoryName =" G3-S2"}, new Tes tClass(){Name =" Items12",IsExpanded = false,GroupingCategoryName =" G3",SubGroupingCategoryName =" G3-S2"},}; Hello!I'm doing some research but I am not able to find a solution to my problem.I have a ViewModel with this property public ICollectionView Inputs{ get { m_CollectionViewSource.Source = m_InputsCollection; m_ICollectionView = m_CollectionViewSource.View; m_ICollectionView.GroupDescriptions.Add(new PropertyGroupDescription("GroupingCategoryName")); m_ICollectionView.GroupDescriptions.Add(new PropertyGroupDescription("SubGroupingCategoryName")); return m_ICollectionView; } }}m_InputsCollection is an ObservableCollection of view models that have a property "IsExpanded"m_ICollectionView is of type ICollectionViewm_CollectionViewSource is of type CollectionViewSource I have a UserControl in which I bind to the Inputs<Grid DataContext="{Binding Path=Inputs}"> <!--right side of the page with active content--> <Grid> <ScrollViewer> <ContentControl Content="{Binding Path=Inputs}" ContentTemplate="{StaticResource InputsTemplate}"/> </ScrollViewer> </Grid></Grid>Then I have all my styles and templates in a ResourceDictionary:1)Template for the Parent container<DataTemplate x:Key="InputsTemplate" x:Name="InputsTemplate"> <Grid> <ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource ViewModelChildTemplate}"> <ItemsControl.GroupStyle> <GroupStyle ContainerStyle="{StaticResource ContainerStyle}"/> </ItemsControl.GroupStyle> </ItemsControl> </Grid> </DataTemplate>2)The Group style:<Style x:Key="ContainerStyle" TargetType="{x:Type GroupItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Expander Header="{Binding Name}" IsExpanded="{Binding Items[0].IsExpanded, diag:PresentationTraceSources.TraceLevel=High}"> <ItemsPresenter /> </Expander> </ControlTemplate> </Setter.Value> </Setter></Style>3) Style for the Expander: <Style TargetType="{x:Type Expander}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Expander}"> <!--Grid containing the expander and the content to be expanded--> <Grid> <Grid.RowDefinitions> <RowDefinition Height="{StaticResource ExpanderRowHeight}" /> <RowDefinition x:Name="ContentRow" Height="0" /> </Grid.RowDefinitions> <!-- Border for the header group--> <Border x:Name="Border" Grid.Row="0" BorderThickness="1" Margin="{StaticResource HeaderGroupMargin}" CornerRadius="2,2,0,0"> <Grid> <!-- toggle button expander--> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <ToggleButton VerticalAlignment="Center" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Margin="{StaticResource HeaderToggleButtonMargin}" OverridesDefaultStyle="True" Template="{StaticResource ExpanderToggleButton}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"> <ToggleButton.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="{DynamicResource ControlLightColor}" Offset="0" /> <GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1" /> </LinearGradientBrush> </ToggleButton.Background> </ToggleButton> </Grid> </Border> <!-- Border for the content (the children) --> <Border x:Name="Content" Grid.Row="1" BorderThickness="1,0,1,1" CornerRadius="0,0,2,2"> <ContentPresenter Margin="4" /> </Border> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsExpanded" Value="True"> <Setter TargetName="ContentRow" Property="Height" Value="{Binding Height, ElementName=Content}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>The result I have is a grouping on two levels:The only problem I have now is preserve the state of the expander.As I said, m_InputsCollection is an ObservableCollection of view models that have a property "IsExpanded"If I bind the expander to Items[0].IsExpanded I can see (by enabling binding trace) that the bind works for the inner itemsthat are in the subgroup (that is "Filters" "Domain" "Advanced" in the picture above) but for the "Force" I got a binding error:BindingExpression path error: 'IsExpanded' property not found on 'object' ''CollectionViewGroupInternal' (HashCode=19753106)'. BindingExpression:Path=Items[0].IsExpanded; DataItem='CollectionViewGroupInternal' (HashCode=53740895); target element is 'Expander' (Name=''); target property is 'IsExpanded' (type 'Boolean')I don't understand what's going on :/The full trace of the binding is here:https://pastebin.com/raw/TKEXq26aThanks for your time.GianpaoloEDIT: I know that probably the binding to Items[0].IsExpanded is not correct, I was just trying to understand what's happen with the trace enabled Tom Waits :) 解决方案 Hi gianpaolo72,>>that are in the subgroup (that is "Filters" "Domain" "Advanced" in the picture above) but for the "Force" I got a binding error:The reason for the success of the binding on sub group is the XAML binding can find the fist item with your custom IsExpanded property in the data context. So for the expander of the first root group("Force" in your case), it will find the IsExpanded property in the data context of the fist sub group("Filters" in your case), but, please notice that there is no such property inside its data context, only you can use is theExpander.IsExpanded control property.So how to fix this issue? We can use value converter in MVVM design mode.I wrote a value converter to traverse all sub-items, for example, if there is any sub group which has been expanded, the current expander should also be expanded:public class CheckExpandConverter : IValueConverter { private bool calcIsExpandedFromItems(CollectionViewGroup cvg) { var isExp = false; if (cvg != null && cvg.Items.Count > 0) { foreach(var item in cvg.Items) { if (item is TestClass) { isExp |= (item as TestClass).IsExpanded; } } } return isExp; } public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is ReadOnlyObservableCollection<Object>) { var isExp = false; var oc = value as ReadOnlyObservableCollection<Object>; foreach(var t in oc) { if (t is TestClass) isExp |= (t as TestClass).IsExpanded; if (t is CollectionViewGroup) isExp |= calcIsExpandedFromItems(t as CollectionViewGroup); } return isExp; } return false; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }We need to change the GroupItem syle as below:<cv:CheckExpandConverter x:Key="CheckExpandConverter" /> <Style x:Key="ContainerStyle" TargetType="{x:Type GroupItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Expander Header="{Binding Name}" IsExpanded="{Binding Items, Converter={StaticResource CheckExpandConverter}, Mode=OneWay}"> <ItemsPresenter /> </Expander> </ControlTemplate> </Setter.Value> </Setter> </Style>Screenshot:Here is my model:public class TestClass { public string Name { get; set; } public bool IsExpanded { get; set; } public string GroupingCategoryName { get; set; } public string SubGroupingCategoryName { get; set; } }Test collection:m_InputsCollection = new ObservableCollection<TestClass>() { new TestClass(){ Name="Items1", IsExpanded=true, GroupingCategoryName="G1", SubGroupingCategoryName = "G1-S1"}, new TestClass(){ Name="Items2", IsExpanded=false, GroupingCategoryName="G1", SubGroupingCategoryName = "G1-S1"}, new TestClass(){ Name="Items3", IsExpanded=false, GroupingCategoryName="G1", SubGroupingCategoryName = "G1-S2"}, new TestClass(){ Name="Items4", IsExpanded=false, GroupingCategoryName="G1", SubGroupingCategoryName = "G1-S2"}, new TestClass(){ Name="Items5", IsExpanded=false, GroupingCategoryName="G2", SubGroupingCategoryName = "G2-S1"}, new TestClass(){ Name="Items6", IsExpanded=false, GroupingCategoryName="G2", SubGroupingCategoryName = "G2-S1"}, new TestClass(){ Name="Items7", IsExpanded=true, GroupingCategoryName="G2", SubGroupingCategoryName = "G2-S2"}, new TestClass(){ Name="Items8", IsExpanded=false, GroupingCategoryName="G2", SubGroupingCategoryName = "G2-S2"}, new TestClass(){ Name="Items9", IsExpanded=false, GroupingCategoryName="G3", SubGroupingCategoryName = "G3-S1"}, new TestClass(){ Name="Items10", IsExpanded=false, GroupingCategoryName="G3", SubGroupingCategoryName = "G3-S1"}, new TestClass(){ Name="Items11", IsExpanded=true, GroupingCategoryName="G3", SubGroupingCategoryName = "G3-S2"}, new TestClass(){ Name="Items12", IsExpanded=false, GroupingCategoryName="G3", SubGroupingCategoryName = "G3-S2"}, }; 这篇关于GroupStyle和Expander:在数据模型中保存IsExpanded状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-27 07:03