我有一个viewModel列表,我想在ItemControl中显示
ItemsControl的ItemPanel设置为<Canvas>
,元素是不同类型的ViewModel,它们都从一个ViewModel(ElementViewModel)继承Left
,Top
,{{ 1}},Width
和Height
属性。
元素的位置由样式设置:
Elements
项目具有不同类型,并且DataTemplates
检索视图<ItemsControl ItemsSource="{Binding Elements}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
现在的问题是,我希望以有限的深度显示这些元素的子元素。 我试图将我的ItemsControl移动到一个自定义控件,然后将其嵌入到我的每个元素视图中,但在这种情况下的reccurency不受任何方式的限制,导致显示所有元素包含所有子元素和性能不佳。
我如何实现目标?
答案 0 :(得分:1)
我们有一个树数据结构,想要显示它,但不要比特定级别更深。对?
首先,我们需要以某种方式获得元素的深度 - 它与根的距离。让我们的元素具有额外的属性int Depth
。
public class ElementViewModel : INotifyPropertyChanged
{
public int Depth {get;set;}
public IEnumerable<ElementViewModel> Elements {get; set;}
...
}
请注意,当VM未实现INotifyPropertyChanged
或未从DependencyObject
继承实施相应的DependecnyProperty
内存泄漏may occur时。
那么,下一步是什么? Multibinding。与简单的绑定不同,MultiBinding允许您在IMultiValueConverter的帮助下将多个值转换为一个。
为什么我们需要它?这个想法非常简单,我们希望在达到所需的深度级别时返回嵌套元素的空集合。
public class ElementsConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var elements = values[0] as IEnumerable<ElementViewModel>;
var depth = (int)values[1];
if (depth <= 9) // depthLimit can be passed through parameter (MultiBinding.ConverterParameter property) or via AmbientContext. Actually many ways exist.
{
return elements;
}
else
{
return new ElementViewModel[0];
}
}
public object[] ConverBack(bject value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<ItemsControl>
<ItemsControl.ItemsSource>
<MultiBinding Mode="OneWay">
<MultiBinding.Converter>
<localNamespace:ElementsConverter/>
</MultiBinding.Converter>
<Binding Path="Elements"/>
<Binding Path="Depth"/>
</MultiBinding>
</ItemsControl.ItemsSource>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Top}"/>
<Setter Property="Width" Value="{Binding Width}"/>
<Setter Property="Height" Value="{Binding Height}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>