嵌套深度有限的视觉元素

时间:2014-11-12 09:09:01

标签: c# wpf

我有一个viewModel列表,我想在ItemControl中显示

ItemsControl的ItemPanel设置为<Canvas>,元素是不同类型的ViewModel,它们都从一个ViewModel(ElementViewModel)继承LeftTop,{{ 1}},WidthHeight属性。 元素的位置由样式设置:

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不受任何方式的限制,导致显示所有元素包含所有子元素和性能不佳。

我如何实现目标?

1 个答案:

答案 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>