WPF Treeview项目可见性附加行为

时间:2014-02-20 10:12:41

标签: c# wpf xaml mvvm treeview

我正在写一个附加行为

public class resizingBehavior : Behavior<ItemsControl>

确定树视图中的可见项目数。

OnAttached方法

protected override void OnAttached()
{
   base.OnAttached();
   AssociatedObject.Loaded += AssociatedObject_Loaded;
}

内部AssociatedObject.Loaded事件处理程序

我正在为我的treeview控件挂钩一个尺寸更改的事件处理程序

private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
   var itemsControl = (ItemsControl)sender;

   _sizeChangedEventHandler = (s, f) => ComputeVisibleItemsCount(itemsControl);

   var treeListView = AssociatedObject as TreeListView;        
   treeListView.SizeChanged += _sizeChangedEventHandler;

   itemsControl.Loaded -= AssociatedObject_Loaded;
}

当我加载应用程序和调整树视图大小时,会调用这些事件。我的问题在于计算树视图中的可见项目。不幸的是,IsVisible属性并没有给我一个正确的结果。我使用了In WPF, how can I determine whether a control is visible to the user?

中建议的答案

但这似乎对我不起作用。它给了我一个错误的结果。

确定itemscontrol中实际可查看项目的任何良好实践或标准解决方案?调整大小和滚动时?顺便说一下,我正在使用反应性集合来查看我的树视图项目。

1 个答案:

答案 0 :(得分:0)

这是工作解决方案。欢迎任何人重构和更正代码。

[Localizable(false)]
public class ItemsControlResizingBehavior : Behavior<ItemsControl>
{
    public static readonly DependencyProperty VisibleItemsCountProperty =
        DependencyProperty.Register("VisibleItemsCount",
            typeof(int),
            typeof(ItemsControlResizingBehavior),
            new FrameworkPropertyMetadata(0, OnSizeChanged));

    public int VisibleItemsCount
    {
        get { return (int)GetValue(VisibleItemsCountProperty); }
        set { SetValue(VisibleItemsCountProperty, value); }
    }

    private static void OnSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue == null)
            return;
        var behavior = (ItemsControlResizingBehavior)d;

        if (behavior.AssociatedObject == null)
            return;

        behavior.ComputeVisibleItemsCount(behavior.AssociatedObject);
    }

    private SizeChangedEventHandler _listViewSizeChangedEventHandler;

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        var itemsControl = (ItemsControl)sender;

        _listViewSizeChangedEventHandler = (x, y) => ComputeVisibleItemsCount(itemsControl);

        var treeListView = AssociatedObject as TreeListView;
        if (treeListView != null)
            treeListView.SizeChanged += _listViewSizeChangedEventHandler;

        var listView = AssociatedObject as ListView;
        if (listView != null)
            listView.SizeChanged += _listViewSizeChangedEventHandler;

        itemsControl.Loaded -= AssociatedObject_Loaded;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        var treeListView = AssociatedObject as TreeListView;
        if (treeListView != null)
            treeListView.SizeChanged -= _listViewSizeChangedEventHandler;

        var listView = AssociatedObject as ListView;
        if (listView != null)
            listView.SizeChanged -= _listViewSizeChangedEventHandler;
    }

    private void ComputeVisibleItemsCount(ItemsControl itemsControl)
    {
        if (itemsControl.Items.Count <= 0)
            return;

        if (itemsControl is TreeListView)
        {
            VisibleItemsCount = GetTreeViewItems(itemsControl).Count(x => x.IsVisibleInUI(itemsControl));
        }
        if (itemsControl is ListView)
        {
            VisibleItemsCount = GetListViewItems(itemsControl).Count(x => x.IsVisibleInUI(itemsControl));
        }
    }

    private static IEnumerable<TreeViewItem> GetTreeViewItems(ItemsControl tree)
    {
        for (int i = 0; i < tree.Items.Count; i++)
        {
            var item = (TreeViewItem)tree.ItemContainerGenerator.ContainerFromIndex(i);
            if (item == null)
                continue;

            yield return item;

            foreach (TreeViewItem subItem in GetTreeViewItems(item))
            {
                yield return subItem;
            }
        }
    }

    private static IEnumerable<ListViewItem> GetListViewItems(ItemsControl list)
    {
        for (int i = 0; i < list.Items.Count; i++)
        {
            var item = (ListViewItem)list.ItemContainerGenerator.ContainerFromIndex(i);
            if (item == null)
                continue;

            yield return item;
        }
    }
}