WPF 组织机构摄像机树 全量加载 大数据量 分页加载摄像机节点


WPF 组织机构摄像机树 全量加载 大数据量 分页加载摄像机节点

完整代码:

https://gitee.com/s0611163/WpfTreeDemo

性能:
8000组织机构20万摄像机,全量加载仅需0.8秒
8000组织机构125万摄像机,全量加载仅需4秒

主要代码:

TreeNodeData.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Models
{
    /// <summary>
    /// 树节点数据
    /// </summary>
    public class TreeNodeData : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private bool _IsVisible = true;
        /// <summary>
        /// 是否可见
        /// </summary>
        public bool IsVisible
        {
            get
            {
                return _IsVisible;
            }
            set
            {
                _IsVisible = value;
                OnPropertyChanged("IsVisible");
            }
        }

        private bool _IsSelected = false;
        /// <summary>
        /// 是否已选择
        /// </summary>
        public bool IsSelected
        {
            get
            {
                return _IsSelected;
            }
            set
            {
                _IsSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }

        private bool _IsLoading = false;
        /// <summary>
        /// 是否正在加载子节点
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return _IsLoading;
            }
            set
            {
                _IsLoading = value;
                OnPropertyChanged("IsLoading");
            }
        }

        private bool _IsChildLoaded = false;
        /// <summary>
        /// 子节点是否已加载完毕
        /// </summary>
        public bool IsChildLoaded
        {
            get
            {
                return _IsChildLoaded;
            }
            set
            {
                _IsChildLoaded = value;
                OnPropertyChanged("IsChildLoaded");
            }
        }

        private bool _IsLeaf = false;
        /// <summary>
        /// 是否是叶子节点
        /// </summary>
        public bool IsLeaf
        {
            get
            {
                return _IsLeaf;
            }
            set
            {
                _IsLeaf = value;
                OnPropertyChanged("IsLeaf");
            }
        }

        private bool _IsCheckable = false;
        /// <summary>
        /// 是否显示CheckBox
        /// </summary>
        public bool IsCheckable
        {
            get
            {
                return _IsCheckable;
            }
            set
            {
                _IsCheckable = value;
                OnPropertyChanged("IsCheckable");
            }
        }

        private bool _IsExpanded = false;
        /// <summary>
        /// 是否展开
        /// </summary>
        public bool IsExpanded
        {
            get
            {
                return _IsExpanded;
            }
            set
            {
                _IsExpanded = value;
                OnPropertyChanged("IsExpanded");
            }
        }

        private TreeNodeData _parent;
        /// <summary>
        /// 父节点数据
        /// </summary>
        public TreeNodeData Parent
        {
            get
            {
                return _parent;
            }
            set
            {
                _parent = value;
                OnPropertyChanged("Parent");
            }
        }

        private ObservableCollection<TreeNodeData> _children = new ObservableCollection<TreeNodeData>();
        /// <summary>
        /// 子节点数据集合
        /// </summary>
        public ObservableCollection<TreeNodeData> Children
        {
            get
            {
                return _children;
            }
            set
            {
                _children = value;
                OnPropertyChanged("Parent");
            }
        }

        private int _PageSize = 25;
        /// <summary>
        /// 每页数据条数
        /// </summary>
        public int PageSize
        {
            get
            {
                return _PageSize;
            }
            set
            {
                _PageSize = value;
                OnPropertyChanged("PageSize");
            }
        }

        private bool _SearchMode = false;
        /// <summary>
        /// 搜索模式
        /// </summary>
        public bool SearchMode
        {
            get
            {
                return _SearchMode;
            }
            set
            {
                _SearchMode = value;
                OnPropertyChanged("SearchMode");
                OnPropertyChanged("PageCtrlVisible");
            }
        }

        /// <summary>
        /// 是否显示分页控件
        /// </summary>
        public Visibility PageCtrlVisible
        {
            get
            {
                if (!SearchMode && IsOrgLeaf && CameraCount > 0)
                {
                    return Visibility.Visible;
                }
                return Visibility.Collapsed;
            }
        }

        /// <summary>
        /// 是否显示展开按钮
        /// </summary>
        public Visibility ExpandVisible
        {
            get
            {
                if (IsOrgLeaf)
                {
                    if (CameraCount > 0)
                    {
                        return Visibility.Visible;
                    }
                    else
                    {
                        return Visibility.Hidden;
                    }
                }
                else
                {
                    if (Children.Count > 0)
                    {
                        return Visibility.Visible;
                    }
                    else
                    {
                        return Visibility.Hidden;
                    }
                }
            }
        }

        private bool _IsOrgLeaf = false;
        /// <summary>
        /// 是否是组织机构叶子节点
        /// </summary>
        public bool IsOrgLeaf
        {
            get
            {
                return _IsOrgLeaf;
            }
            set
            {
                _IsOrgLeaf = value;
                OnPropertyChanged("IsOrgLeaf");
            }
        }

        private string _level;
        /// <summary>
        /// 组织机构等级
        /// </summary>
        public string Level
        {
            get
            {
                return _level;
            }
            set
            {
                _level = value;
                OnPropertyChanged("Level");
            }
        }

        private bool _IsOnline = true;
        /// <summary>
        /// 像机是否在线
        /// </summary>
        public bool IsOnline
        {
            get
            {
                return _IsOnline;
            }
            set
            {
                _IsOnline = value;
                OnPropertyChanged("IsOnline");
            }
        }

        private List<TreeNodeData<PtCameraInfo>> _cameraNodeDataList = new List<TreeNodeData<PtCameraInfo>>();
        /// <summary>
        /// 该节点下摄像机集合
        /// </summary>
        public List<TreeNodeData<PtCameraInfo>> CameraNodeDataList
        {
            get
            {
                return _cameraNodeDataList;
            }
            set
            {
                _cameraNodeDataList = value;
            }
        }

        private int _CameraCount;
        /// <summary>
        /// 该节点下像机总数
        /// </summary>
        public int CameraCount
        {
            get
            {
                return _CameraCount;
            }
            set
            {
                _CameraCount = value;
                OnPropertyChanged("CameraCount");

                CameraCountString = string.Format("({0}/{1})", OnlineCameraCount, CameraCount);
            }
        }

        private int _OnlineCameraCount;
        /// <summary>
        /// 该节点下在线像机总数
        /// </summary>
        public int OnlineCameraCount
        {
            get
            {
                return _OnlineCameraCount;
            }
            set
            {
                _OnlineCameraCount = value;
                OnPropertyChanged("OnlineCameraCount");

                CameraCountString = string.Format("({0}/{1})", OnlineCameraCount, CameraCount);
            }
        }

        private string _CameraCountString;
        /// <summary>
        /// 该节点下像机总数String
        /// </summary>
        public string CameraCountString
        {
            get
            {
                return _CameraCountString;
            }
            set
            {
                _CameraCountString = value;
                OnPropertyChanged("CameraCountString");
            }
        }

        /// <summary>
        /// 树节点数据 构造函数
        /// </summary>
        public TreeNodeData()
        {

        }

        protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}
View Code

TreeNodeDataT.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Models
{
    /// <summary>
    /// 树节点数据
    /// </summary>
    public class TreeNodeData<T> : TreeNodeData
    {
        private T _info;
        /// <summary>
        /// 业务数据
        /// </summary>
        public T Info
        {
            get
            {
                return _info;
            }
            set
            {
                _info = value;
                OnPropertyChanged("Info");
            }
        }

        public TreeNodeData(T info)
        {
            _info = info;
        }
    }
}
View Code

TreeItemContainerStyleSelector.cs:

using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Converter
{
    public class TreeItemContainerStyleSelector : StyleSelector
    {
        public override Style SelectStyle(object item, DependencyObject container)
        {
            FrameworkElement frameworkElement = container as FrameworkElement;

            if (item is TreeNodeData<PtOrgInfo>)
            {
                return frameworkElement.FindResource("orgItemStyle") as Style;
            }
            else
            {
                return frameworkElement.FindResource("cameraItemStyle") as Style;
            }
        }
    }
}
View Code

OrgCameraTree.xaml:

实现的关键是使用了WPF的HierarchicalDataTemplate和TreeView的ItemContainerStyleSelector属性

<UserControl x:Class="Controls.OrgCameraTree"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             xmlns:local="clr-namespace:Controls"
             xmlns:converter="clr-namespace:Converter"
             xmlns:models="clr-namespace:Models"
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <converter:TreeItemContainerStyleSelector x:Key="styleSelector"/>
    </UserControl.Resources>
    <Grid>
        <TreeView x:Name="orgTree" ItemContainerStyleSelector="{StaticResource styleSelector}" >
            <TreeView.Resources>
                <converter:BoolToVisibilityConverter x:Key="boolToVisibilityConverter"/>
                <converter:CountToVisibilityConverter x:Key="countToVisibilityConverter"/>
                <converter:CameraToTextColorConverter x:Key="cameraToTextColorConverter"/>
                <converter:CameraToImageConverter x:Key="cameraToImageConverter"/>
                <converter:OrgLevelToImageConverter x:Key="orgLevelToImageConverter"/>

                <ControlTemplate x:Key="menuItemTemplate" TargetType="MenuItem">
                    <Border Name="bd" Height="30" Background="Transparent">
                        <StackPanel Orientation="Horizontal">
                            <Image x:Name="img" Stretch="None" Margin="10,0,10,0" Source="/Images/二级菜单左箭头.png"></Image>
                            <TextBlock x:Name="tb" Margin="0,0,10,0" Foreground="#fff" VerticalAlignment="Center" Text="{Binding Header, RelativeSource={RelativeSource TemplatedParent}}"/>
                        </StackPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="bd" Property="Background" Value="#99001133" />
                            <Setter TargetName="tb" Property="Foreground" Value="#ff5e5e" />
                            <Setter TargetName="tb" Property="Margin" Value="0,0,9,0" />
                            <Setter TargetName="img" Property="Source" Value="/Images/左箭头_选中.png"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
                <ControlTemplate x:Key="menuSeperatorTemplate" TargetType="Separator">
                    <Border Background="#6fff">
                    </Border>
                </ControlTemplate>
                <ControlTemplate x:Key="menuTemplate" TargetType="ContextMenu">
                    <Border Name="bd" Background="#99001133">
                        <ItemsPresenter/>
                    </Border>
                </ControlTemplate>

                <Style x:Key="orgItemStyle" TargetType="{x:Type TreeViewItem}">
                    <Style.Setters>
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded}"></Setter>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                                    <StackPanel Visibility="{Binding IsVisible,Converter={StaticResource boolToVisibilityConverter}}">
                                        <StackPanel Orientation="Horizontal"  Height="20">
                                            <ToggleButton Checked="toggleButton_Checked" Name="toggleButton" Focusable="True" PreviewMouseLeftButtonDown="toggleButton_PreviewMouseLeftButtonDown" IsChecked="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsExpanded,Mode=TwoWay}"
                                                          Visibility="{Binding ExpandVisible}" IsTabStop="False" >
                                                <ToggleButton.Template>
                                                    <ControlTemplate TargetType="{x:Type ToggleButton}" >
                                                        <Border   Height="20" Width="20" Background="Transparent">
                                                            <Path Height="6" Width="6" HorizontalAlignment="Center" Name="expander" RenderTransformOrigin="0.5,0.5" Data="M0,0 L0,6 L6,0 z" Stroke="White" StrokeThickness="1"  VerticalAlignment="Center"  Visibility="{Binding IsLeaf,Converter={StaticResource boolToVisibilityConverter},ConverterParameter=false}">
                                                            </Path>
                                                        </Border>
                                                        <ControlTemplate.Triggers>
                                                            <Trigger Property="IsChecked" Value="true">
                                                                <Setter Property="RenderTransform" TargetName="expander">
                                                                    <Setter.Value>
                                                                        <RotateTransform Angle="180"/>
                                                                    </Setter.Value>
                                                                </Setter>
                                                                <Setter Property="Fill" TargetName="expander" Value="White">
                                                                </Setter>
                                                            </Trigger>
                                                            <Trigger Property="IsChecked" Value="false">
                                                                <Setter Property="RenderTransform" TargetName="expander">
                                                                    <Setter.Value>
                                                                        <RotateTransform Angle="135"/>
                                                                    </Setter.Value>
                                                                </Setter>
                                                                <Setter Property="Fill" TargetName="expander" Value="White">
                                                                </Setter>
                                                            </Trigger>
                                                        </ControlTemplate.Triggers>
                                                    </ControlTemplate>
                                                </ToggleButton.Template>
                                            </ToggleButton>
                                            <CheckBox VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext}" IsChecked="{Binding IsSelected,Mode=TwoWay}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" Click="CheckBox_Click" Margin="3 0 0 0" Visibility="{Binding IsCheckable, Converter={StaticResource boolToVisibilityConverter}}" IsTabStop="False" />
                                            <StackPanel Margin="5 0 0 0" Orientation="Horizontal"  Name="panel">
                                                <Image Height="15" Width="15" Source="{Binding Info.orgLevel,Converter={StaticResource orgLevelToImageConverter}}" VerticalAlignment="Center"/>
                                                <TextBlock x:Name="textBlock" Foreground="White" Margin="5 0 0 0" Text="{Binding Info.orgName}" VerticalAlignment="Center"/>
                                                <TextBlock x:Name="textCount" Foreground="White" Margin="5 0 0 0" Text="{Binding CameraCountString}" VerticalAlignment="Center"/>
                                                <Viewbox Height="15" Margin="5 0 0 0" Visibility="{Binding IsLoading,Converter={StaticResource boolToVisibilityConverter}}">
                                                    <local:LoadingWait/>
                                                </Viewbox>
                                            </StackPanel>
                                        </StackPanel>
                                        <Grid x:Name="itemspanel" Visibility="Collapsed" Margin="15 0 0 0">
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="auto"/>
                                                <RowDefinition Height="auto"/>
                                            </Grid.RowDefinitions>
                                            <ItemsPresenter/>
                                            <local:SimplePageControl x:Name="pageCtrl" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="30 0 0 0" TextColor="White"  
                                                Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext.PageCtrlVisible}" 
                                                Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext}" 
                                                TotalRecords="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext.CameraCount}" 
                                                RecordsPerPage="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext.PageSize}" 
                                                evtPageChanged="pageCtrl_evtPageChanged" />
                                        </Grid>
                                    </StackPanel>
                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsSelected" Value="true">
                                            <Setter Property="Background" TargetName="textBlock" Value="#FF497AE1"/>
                                            <Setter Property="Foreground" TargetName="textBlock" Value="White"/>
                                        </Trigger>
                                        <Trigger Property="IsExpanded" Value="true">
                                            <Setter TargetName="itemspanel" Property="Visibility" Value="Visible"/>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style.Setters>
                </Style>

                <Style x:Key="cameraItemStyle" TargetType="{x:Type TreeViewItem}">
                    <Style.Setters>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                                    <StackPanel Visibility="{Binding IsVisible,Converter={StaticResource boolToVisibilityConverter}}">
                                        <StackPanel Orientation="Horizontal" Height="20" Margin="10 0 0 0">
                                            <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay}" Visibility="{Binding IsCheckable, Converter={StaticResource boolToVisibilityConverter}}" Margin="5 0 0 0" VerticalAlignment="Center" Click="Camera_CheckBox_Click" Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}},Path=DataContext}" IsTabStop="False" />
                                            <StackPanel Margin="5 0 0 0" Orientation="Horizontal"  Name="panel">
                                                <Image x:Name="cameraImg" Height="16" Width="16" Source="{Binding Info,Converter={StaticResource cameraToImageConverter}}"  VerticalAlignment="Center"/>
                                                <TextBlock MouseLeftButtonDown="textBlock_MouseLeftButtonDown" x:Name="textBlock" Foreground="{Binding IsOnline,Converter={StaticResource cameraToTextColorConverter}}" Margin="5 0 0 0" Tag="{Binding Info}" Text="{Binding Info.CAMERA_NAME}" VerticalAlignment="Center" />
                                            </StackPanel>
                                        </StackPanel>
                                        <ItemsPresenter  Name="itemspanel" Visibility="Collapsed" Margin="10 0 0 0"/>
                                        <StackPanel.ContextMenu>
                                            <ContextMenu Template="{StaticResource menuTemplate}">
                                                <MenuItem Name="menuShowDetails" Header="摄像机详细信息" Template="{StaticResource menuItemTemplate}" Tag="{Binding Info}" Click="menuShowDetails_Click"></MenuItem>
                                            </ContextMenu>
                                        </StackPanel.ContextMenu>
                                    </StackPanel>
                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsSelected" Value="true">
                                            <Setter Property="Background" TargetName="textBlock" Value="#FF497AE1"/>
                                            <Setter Property="Foreground" TargetName="textBlock" Value="White"/>
                                        </Trigger>
                                        <Trigger Property="IsExpanded" Value="true">
                                            <Setter TargetName="itemspanel" Property="Visibility" Value="Visible"/>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style.Setters>
                </Style>
            </TreeView.Resources>
            <TreeView.Template>
                <ControlTemplate>
                    <ScrollViewer HorizontalScrollBarVisibility="Auto" MinHeight="{Binding ElementName=orgTree,Path=ActualHeight}" MinWidth="{Binding ElementName=orgTree, Path=ActualWidth}">
                        <ItemsPresenter></ItemsPresenter>
                    </ScrollViewer>
                </ControlTemplate>
            </TreeView.Template>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type models:TreeNodeData}" ItemsSource="{Binding Path=Children}" ></HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

        <local:LoadingWait VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="loadingWait"/>
    </Grid>
</UserControl>
View Code

OrgCameraTree.xaml.cs:

using Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Controls
{
    /// <summary>
    /// 组织机构摄像机树
    /// </summary>
    public partial class OrgCameraTree : UserControl
    {
        private ObservableCollection<TreeNodeData<PtOrgInfo>> _list;

        public OrgCameraTree()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 加载树节点
        /// </summary>
        public void LoadTree(ObservableCollection<TreeNodeData<PtOrgInfo>> list)
        {
            _list = list;
            this.orgTree.ItemsSource = list;
            loadingWait.Visibility = Visibility.Collapsed;
        }

        #region CheckBox 组织机构选择
        private void CheckBox_Checked(object sender, RoutedEventArgs e)
        {

        }

        private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
        {

        }

        private void CheckBox_Click(object sender, RoutedEventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            TreeNodeData nodeData = checkBox.Tag as TreeNodeData;

            if (checkBox.IsChecked.Value)
            {
                CheckChildren(nodeData, true);
            }
            else
            {
                CheckParent(nodeData.Parent, false);
                CheckChildren(nodeData, false);
            }
        }

        private void CheckChildren(TreeNodeData nodeData, bool check)
        {
            if (nodeData.IsOrgLeaf)
            {
                nodeData.CameraNodeDataList.ForEach(item => item.IsSelected = check);
            }

            nodeData.Children.ToList().ForEach(child =>
            {
                child.IsSelected = check;
                CheckChildren(child, check);
            });
        }

        private void CheckParent(TreeNodeData parent, bool check)
        {
            if (parent != null)
            {
                parent.IsSelected = check;
                CheckParent(parent.Parent, check);
            }
        }
        #endregion

        #region CheckBox 摄像机选择
        private void Camera_CheckBox_Click(object sender, RoutedEventArgs e)
        {
            CheckBox checkBox = sender as CheckBox;
            TreeNodeData nodeData = checkBox.Tag as TreeNodeData;

            if (checkBox.IsChecked.Value)
            {
            }
            else
            {
                CheckParent(nodeData.Parent, false);
            }
        }
        #endregion

        #region toggleButton 展开按钮事件
        private void toggleButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ToggleButton btn = sender as ToggleButton;
            btn.IsChecked = !btn.IsChecked;
            e.Handled = true;
        }

        private void toggleButton_Checked(object sender, RoutedEventArgs e)
        {
            ToggleButton btn = sender as ToggleButton;
        }
        #endregion

        #region pageCtrl_evtPageChanged 分页事件
        /// <summary>
        /// 分页事件
        /// </summary>
        private void pageCtrl_evtPageChanged(object sender, PageChangedEventArgs e)
        {
            SimplePageControl simplePageControl = sender as SimplePageControl;
            TreeNodeData<PtOrgInfo> nodeData = simplePageControl.Tag as TreeNodeData<PtOrgInfo>;
            List<TreeNodeData<PtCameraInfo>> list = GetCameraListPage(nodeData.CameraNodeDataList, nodeData.Info.id, e.PageNow, e.RecordsPerPage);
            nodeData.Children.Clear();
            list.ForEach(item =>
            {
                nodeData.Children.Add(item);
            });
        }
        #endregion

        #region GetCameraListPage 分页获取像机数据
        /// <summary>
        /// 分页获取像机数据
        /// </summary>
        private List<TreeNodeData<PtCameraInfo>> GetCameraListPage(List<TreeNodeData<PtCameraInfo>> cameraNodeDataList, long orgId, int currentPage, int pageSize)
        {
            List<TreeNodeData<PtCameraInfo>> result = new List<TreeNodeData<PtCameraInfo>>();

            int start = pageSize * (currentPage - 1);
            int end = pageSize * currentPage - 1;

            for (int i = start; i <= end; i++)
            {
                if (i < cameraNodeDataList.Count)
                {
                    result.Add(cameraNodeDataList[i]);
                }
            }

            return result;
        }
        #endregion

        #region textBlock_MouseLeftButtonDown 拖放
        private void textBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            try
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    //如果是录像回放,不加载拖拽事件
                    if (false)
                    {
                        return;
                    }
                    PtCameraInfo info = (sender as TextBlock).Tag as PtCameraInfo;
                    DragDrop.DoDragDrop(this, info, DragDropEffects.Copy);
                }
            }
            catch (Exception ex)
            {

            }
        }
        #endregion

        #region menuShowDetails_Click 显示摄像机详细信息
        private void menuShowDetails_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = sender as MenuItem;
            PtCameraInfo cameraInfo = menuItem.Tag as PtCameraInfo;
            MessageBox.Show(cameraInfo.CAMERA_NAME);
        }
        #endregion

        #region 获取选择的摄像机
        /// <summary>
        /// 获取选择的摄像机
        /// </summary>
        public List<PtCameraInfo> GetSelectedCameras()
        {
            List<PtCameraInfo> result = new List<PtCameraInfo>();

            foreach (TreeNodeData item in _list)
            {
                result.AddRange(GetSelectedCameras(item));
            }

            return result;
        }

        private List<PtCameraInfo> GetSelectedCameras(TreeNodeData nodeData)
        {
            List<PtCameraInfo> result = new List<PtCameraInfo>();

            if (nodeData.IsOrgLeaf)
            {
                foreach (TreeNodeData<PtCameraInfo> item in nodeData.CameraNodeDataList)
                {
                    if (item.IsSelected)
                    {
                        result.Add(item.Info);
                    }
                }
            }
            else
            {
                foreach (TreeNodeData item in nodeData.Children)
                {
                    result.AddRange(GetSelectedCameras(item));
                }
            }

            return result;
        }
        #endregion

        #region 获取选择的组织机构
        /// <summary>
        /// 获取选择的摄像机
        /// </summary>
        public List<PtOrgInfo> GetSelectedOrgs()
        {
            List<PtOrgInfo> result = new List<PtOrgInfo>();

            foreach (TreeNodeData item in _list)
            {
                result.AddRange(GetSelectedOrgs(item));
            }

            return result;
        }

        private List<PtOrgInfo> GetSelectedOrgs(TreeNodeData nodeData)
        {
            List<PtOrgInfo> result = new List<PtOrgInfo>();

            if (nodeData is TreeNodeData<PtOrgInfo>)
            {
                PtOrgInfo orgInfo = (nodeData as TreeNodeData<PtOrgInfo>).Info;
                if (nodeData.IsSelected)
                {
                    result.Add(orgInfo);
                }

                foreach (TreeNodeData item in nodeData.Children)
                {
                    result.AddRange(GetSelectedOrgs(item));
                }
            }

            return result;
        }
        #endregion

        #region 查询节点
        /// <summary>
        /// 查询节点
        /// </summary>
        public void Search(string text)
        {
            this.loadingWait.Visibility = Visibility.Visible;

            foreach (TreeNodeData item in _list)
            {
                ClearSearch(item); //清空查询结果
            }

            if (!string.IsNullOrWhiteSpace(text))
            {
                Search(text, null);
            }

            this.loadingWait.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 查询节点
        /// </summary>
        private bool Search(string text, TreeNodeData nodeData = null)
        {
            bool result = false; //是否查询到满足条件的节点

            if (nodeData == null)
            {
                foreach (TreeNodeData<PtOrgInfo> item in _list) //遍历根节点
                {
                    //item.NodeData.CameraCountVisible = Visibility.Collapsed; //隐藏像机数

                    bool bl = Search(text, item); //递归查询其子节点
                    if (item.Info.orgName.Contains(text)) //当前节点满足条件
                    {
                        item.IsVisible = true;
                    }
                    else
                    {
                        if (bl) //子节点查询到结果
                        {
                            item.IsVisible = true;
                        }
                        else //子节点没有查询到结果
                        {
                            item.IsVisible = false;
                        }
                    }
                }
            }
            else
            {
                //nodeData.CameraCountVisible = Visibility.Collapsed; //隐藏像机数

                if (nodeData.IsOrgLeaf)
                {
                    foreach (TreeNodeData<PtCameraInfo> item in nodeData.CameraNodeDataList)
                    {
                        if (item.Info.SHORT_MSG != null && item.Info.SHORT_MSG.Contains(text)) //像机节点满足条件
                        {
                            nodeData.SearchMode = true; //隐藏分页控件
                            item.IsVisible = true; //显示
                            bool exists = false;
                            foreach (TreeNodeData<PtCameraInfo> child in item.Parent.Children)
                            {
                                if (child.Info.ID == item.Info.ID)
                                {
                                    exists = true;
                                    break;
                                }
                            }
                            if (!exists)
                            {
                                item.Parent.Children.Add(item);
                            }
                            result = true;
                        }
                        else
                        {
                            item.IsVisible = false; //不满足查询条件不显示
                        }
                    }
                }
                else
                {
                    foreach (TreeNodeData<PtOrgInfo> item in nodeData.Children)
                    {
                        bool bl = Search(text, item); //递归查询其子节点
                        if (item.Info.orgName.Contains(text)) //当前节点满足条件
                        {
                            item.IsVisible = true;
                            result = true;
                        }
                        else
                        {
                            if (bl) //子节点查询到结果
                            {
                                item.IsVisible = true;
                                result = true;
                            }
                            else //子节点没有查询到结果
                            {
                                item.IsVisible = false;
                            }
                        }
                    }
                }
            }

            return result;
        }
        #endregion

        #region 清空查询
        /// <summary>
        /// 清空查询
        /// </summary>
        private void ClearSearch(TreeNodeData nodeData)
        {
            nodeData.SearchMode = false; //显示分页控件
            nodeData.IsVisible = true;
            if (nodeData.CameraNodeDataList != null && nodeData.CameraNodeDataList.Count > 0)
            {
                foreach (TreeNodeData<PtCameraInfo> child in nodeData.CameraNodeDataList)
                {
                    child.IsVisible = true;
                }

                //分页处理
                List<TreeNodeData<PtCameraInfo>> list = GetCameraListPage(nodeData.CameraNodeDataList, (nodeData as TreeNodeData<PtOrgInfo>).Info.id, 1, nodeData.PageSize);
                nodeData.Children.Clear();
                list.ForEach(item =>
                {
                    nodeData.Children.Add(item);
                });
            }
            else
            {
                foreach (TreeNodeData child in nodeData.Children)
                {
                    ClearSearch(child);
                }
            }
        }
        #endregion

    }
}
View Code

MainWindow.xaml.cs:

using Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Utils;

namespace WpfTreeDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        #region 变量
        private List<PtOrgInfo> orgListAll = new List<PtOrgInfo>();
        private List<PtCameraInfo> cameraListAll = new List<PtCameraInfo>();
        private List<TreeNodeData<PtOrgInfo>> orgNodeDataListFlat = new List<TreeNodeData<PtOrgInfo>>();
        private List<TreeNodeData<PtCameraInfo>> cameraNodeDataList = new List<TreeNodeData<PtCameraInfo>>();
        #endregion

        #region 构造函数
        public MainWindow()
        {
            InitializeComponent();
        }
        #endregion

        #region Window_Loaded
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ShowOrgCameraTree();
        }
        #endregion

        #region Log
        private void Log(string log)
        {
            this.Dispatcher.InvokeAsync(() =>
            {
                txt.AppendText(DateTime.Now.ToString("HH:mm:ss.fff") + " " + log + "\r\n");
                txt.ScrollToEnd();
            });
        }
        #endregion

        // ==== 组织机构摄像机树 ========================================================================================

        #region ShowOrgCameraTree 显示组织机构摄像机树
        /// <summary>
        /// 显示组织机构摄像机树
        /// </summary>
        private void ShowOrgCameraTree(bool bigData = false)
        {
            DateTime dt = DateTime.Now;
            DateTime startTime = DateTime.Now;
            orgListAll = new List<PtOrgInfo>();
            cameraListAll = new List<PtCameraInfo>();
            orgNodeDataListFlat = new List<TreeNodeData<PtOrgInfo>>();
            cameraNodeDataList = new List<TreeNodeData<PtCameraInfo>>();
            ObservableCollection<TreeNodeData<PtOrgInfo>> orgNodeDataList = null;
            this.orgTree.LoadTree(new ObservableCollection<Models.TreeNodeData<Models.PtOrgInfo>>());
            this.orgTree.loadingWait.Visibility = Visibility.Visible;
            Log("============================================================");

            BackWork.RunAsync(() =>
            {
                #region 生成组织机构和摄像机测试数据
                Random rnd = new Random();

                int countI = 20;
                int countJ = 20;
                int countK = 20;

                for (int i = 0; i < countI; i++)
                {
                    long codeI = 10 + i;

                    PtOrgInfo orgI = new PtOrgInfo();
                    orgI.id = codeI;
                    orgI.parId = -1;
                    orgI.orgName = "测试机构" + codeI;
                    orgI.orgLevel = 0;
                    orgListAll.Add(orgI);

                    for (int j = 0; j < countJ; j++)
                    {
                        long codeJ = codeI * 100 + (j + 1);

                        PtOrgInfo orgJ = new PtOrgInfo();
                        orgJ.id = codeJ;
                        orgJ.parId = codeI;
                        orgJ.orgName = "测试机构" + codeJ;
                        orgJ.orgLevel = 1;
                        orgListAll.Add(orgJ);

                        for (int k = 0; k < countK; k++)
                        {
                            long codeK = codeJ * 100 + (k + 1);

                            PtOrgInfo orgK = new PtOrgInfo();
                            orgK.id = codeK;
                            orgK.parId = codeJ;
                            orgK.orgName = "测试机构" + codeK;
                            orgK.orgLevel = 2;
                            orgListAll.Add(orgK);

                            int countCamera;
                            if (i == 0 && j == 0 && k < 2)
                            {
                                countCamera = 105;
                            }
                            else
                            {
                                countCamera = rnd.Next(1, 50);
                            }
                            if (bigData) countCamera = rnd.Next(135, 180);

                            for (int x = 0; x < countCamera; x++)
                            {
                                string cameraId = (codeK * 1000 + (x + 1)).ToString();

                                PtCameraInfo camera = new PtCameraInfo();
                                camera.ID = cameraId;
                                camera.ORG_ID = orgK.id;
                                camera.CAMERA_NAME = "测试像机" + cameraId;
                                camera.SHORT_MSG = camera.CAMERA_NAME;
                                camera.CAMERA_TYPE = rnd.Next(1, 6);
                                camera.CAMERA_STATE = rnd.Next(0, 2).ToString();
                                cameraListAll.Add(camera);
                            }
                        }
                    }
                }
                #endregion

                string timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
                this.Dispatcher.InvokeAsync(() =>
                {
                    Log("第1步,生成测试数据耗时:" + timeStr + "");
                    Log("组织机构总数:" + orgListAll.Count + ",摄像机总数:" + cameraListAll.Count);
                });
                dt = DateTime.Now;

                orgNodeDataList = new ObservableCollection<TreeNodeData<PtOrgInfo>>(CreateNodeData(orgListAll, cameraListAll, out orgNodeDataListFlat, out cameraNodeDataList)); //生成树节点数据

                timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
                this.Dispatcher.InvokeAsync(() =>
                {
                    Log("第2步,生成节点数据耗时:" + timeStr + "");
                });
                dt = DateTime.Now;
            }, () =>
            {
                this.orgTree.LoadTree(orgNodeDataList);

                SetCameraCount(orgNodeDataListFlat, orgListAll, cameraNodeDataList); //设置在摄像机离线数量

                string timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
                Log("第3步,绑定树节点耗时:" + timeStr + "");
                timeStr = DateTime.Now.Subtract(startTime).TotalSeconds.ToString("0.000");
                Log("总耗时:" + timeStr + "");
            }, ex =>
            {
                Log(ex.Message + "\r\n" + ex.StackTrace);
            });
        }
        #endregion

        #region CreateNodeData 创建树节点
        /// <summary>
        /// 创建树节点
        /// </summary>
        private List<TreeNodeData<PtOrgInfo>> CreateNodeData(List<PtOrgInfo> orgListAll, List<PtCameraInfo> cameraListAll, out List<TreeNodeData<PtOrgInfo>> orgNodeDataListFlat, out List<TreeNodeData<PtCameraInfo>> cameraNodeDataList)
        {
            //组织机构节点集合
            List<TreeNodeData<PtOrgInfo>> orgNodeDataList = orgListAll.ConvertAll(org =>
            {
                TreeNodeData<PtOrgInfo> nodeData = new TreeNodeData<PtOrgInfo>(org);
                nodeData.IsCheckable = true;
                return nodeData;
            });

            //摄像机节点集合
            cameraNodeDataList = cameraListAll.ConvertAll(camera =>
            {
                TreeNodeData<PtCameraInfo> nodeData = new TreeNodeData<PtCameraInfo>(camera);
                nodeData.IsOnline = camera.CAMERA_STATE == "1" ? true : false;
                nodeData.IsCheckable = true;
                return nodeData;
            });

            //组织机构节点字典
            Dictionary<long, TreeNodeData<PtOrgInfo>> dictOrgListAll = orgNodeDataList.ToLookup(item => item.Info.id).ToDictionary(item => item.Key, item => item.First());

            //遍历摄像机节点集合
            foreach (TreeNodeData<PtCameraInfo> cameraNodeData in cameraNodeDataList.ToList())
            {
                long cameraOrgId = Convert.ToInt64(cameraNodeData.Info.ORG_ID);
                if (dictOrgListAll.ContainsKey(cameraOrgId))
                {
                    TreeNodeData<PtOrgInfo> parentNodeData = dictOrgListAll[cameraOrgId];
                    parentNodeData.IsOrgLeaf = true;
                    cameraNodeData.Parent = parentNodeData;
                    if (parentNodeData.Children.Count < cameraNodeData.PageSize)
                    {
                        parentNodeData.Children.Add(cameraNodeData);
                    }
                    parentNodeData.CameraNodeDataList.Add(cameraNodeData);
                    parentNodeData.CameraCount = parentNodeData.CameraNodeDataList.Count;
                }
            }

            //遍历组织机构节点集合
            foreach (TreeNodeData<PtOrgInfo> orgNodeData in orgNodeDataList.ToList())
            {
                if (orgNodeData.Info.parId > 0)
                {
                    if (dictOrgListAll.ContainsKey(orgNodeData.Info.parId))
                    {
                        TreeNodeData<PtOrgInfo> parentNodeData = dictOrgListAll[orgNodeData.Info.parId];
                        orgNodeData.Parent = parentNodeData;
                        parentNodeData.Children.Add(orgNodeData);
                    }
                }
            }

            orgNodeDataListFlat = orgNodeDataList;
            return orgNodeDataList.FindAll(nodeData => nodeData.Info.parId == -1);
        }
        #endregion

        #region SetCameraCount 显示组织机构下的像机总数
        /// <summary>
        /// 显示组织机构下的像机总数
        /// </summary>
        private void SetCameraCount(List<TreeNodeData<PtOrgInfo>> orgNodeDataList, List<PtOrgInfo> orgListAll, List<TreeNodeData<PtCameraInfo>> cameraNodeDataList)
        {
            int _buildPeroid = 0;
            int _treeType = 1;

            Dictionary<long, int> dictCameraCount;
            Dictionary<long, int> dictOnlineCameraCount;
            GetCameraCountDict(orgListAll, cameraNodeDataList, out dictCameraCount, out dictOnlineCameraCount);

            if (_buildPeroid == 0)
            {
                if (_treeType == 1)
                {
                    Dictionary<long, int> dicCameraCount = dictCameraCount;
                    Dictionary<long, int> dicOnlineCameraCount = dictOnlineCameraCount;

                    foreach (TreeNodeData<PtOrgInfo> orgNodeData in orgNodeDataList)
                    {
                        PtOrgInfo org = orgNodeData.Info as PtOrgInfo;

                        int nOnline;
                        int nCount;
                        if (dicCameraCount.TryGetValue(org.id, out nCount) && dicOnlineCameraCount.TryGetValue(org.id, out nOnline))
                        {
                            orgNodeData.CameraCount = nCount;
                            orgNodeData.CameraCountString = string.Format("({0}/{1})", nOnline, nCount);
                        }
                    }
                }
                else
                {
                    foreach (TreeNodeData<PtOrgInfo> orgNodeData in orgNodeDataList)
                    {
                        PtOrgInfo org = orgNodeData.Info as PtOrgInfo;

                        int nOnline;
                        int nCount;
                        dictCameraCount.TryGetValue(org.id, out nCount);
                        dictOnlineCameraCount.TryGetValue(org.id, out nOnline);
                        orgNodeData.CameraCount = nCount;
                        orgNodeData.CameraCountString = string.Format("({0}/{1})", nOnline, nCount);
                    }
                }
            }
            else
            {
                foreach (TreeNodeData<PtOrgInfo> orgNodeData in orgNodeDataList)
                {
                    PtOrgInfo org = orgNodeData.Info as PtOrgInfo;

                    int nOnline;
                    int nCount;
                    dictCameraCount.TryGetValue(org.id, out nCount);
                    dictOnlineCameraCount.TryGetValue(org.id, out nOnline);
                    orgNodeData.CameraCount = nCount;
                    orgNodeData.CameraCountString = string.Format("({0}/{1})", nOnline, nCount);
                }
            }
        }

        #endregion 显示组织机构下的像机总数

        #region GetCameraCountDict 计算所有组织机构下的像机数

        /// <summary>
        /// 计算所有组织机构下的像机数
        /// </summary>
        private void GetCameraCountDict(List<PtOrgInfo> orgListAll, List<TreeNodeData<PtCameraInfo>> cameraNodeDataList, out Dictionary<long, int> dictCameraCount, out Dictionary<long, int> dictOnlineCameraCount)
        {
            int _treeType = 1;
            List<PtCameraInfo> cameraListAll = cameraNodeDataList.ConvertAll<PtCameraInfo>(a => a.Info);

            dictCameraCount = new Dictionary<long, int>();
            dictOnlineCameraCount = new Dictionary<long, int>();

            //组织机构字典
            Dictionary<long, PtOrgInfo> dictOrgListAll = orgListAll.ToLookup(item => item.id).ToDictionary(item => item.Key, item => item.First());
            Dictionary<string, PtOrgInfo> dictOrgListAllByOrgName = orgListAll.ToLookup(item => item.orgName).ToDictionary(item => item.Key, item => item.First());

            //初始化数据
            foreach (PtOrgInfo orgInfo in orgListAll)
            {
                dictCameraCount.Add(orgInfo.id, 0);
                dictOnlineCameraCount.Add(orgInfo.id, 0);
            }

            //遍历所有父级组织机构,像机数+1
            Action<PtOrgInfo, Dictionary<long, int>> action = null;
            action = (PtOrgInfo orgInfo, Dictionary<long, int> dict) =>
            {
                PtOrgInfo parentOrg;
                if (dictOrgListAll.TryGetValue(orgInfo.parId, out parentOrg))
                {
                    dict[parentOrg.id]++;
                    action(parentOrg, dict);
                }
            };

            if (_treeType == 5) cameraListAll = cameraListAll.FindAll(a => a.RECODE_SAVE_TYPE == 2 && a.BuildPeriod == 2);

            foreach (TreeNodeData<PtCameraInfo> cameraNodeData in cameraNodeDataList)
            {
                long orgId = -1;
                PtCameraInfo cameraInfo = cameraNodeData.Info;

                if (cameraInfo.ORG_ID.HasValue && cameraNodeData.IsVisible)
                {
                    if (_treeType == 1)
                    {
                        orgId = (long)cameraInfo.ORG_ID.Value;
                    }
                    if (_treeType == 2)
                    {
                        orgId = (long)cameraInfo.KeyUnit;
                    }
                    if (_treeType == 3)
                    {
                        if (!string.IsNullOrWhiteSpace(cameraInfo.Street))
                        {
                            PtOrgInfo orgInfo;
                            if (dictOrgListAllByOrgName.TryGetValue(cameraInfo.Street, out orgInfo))
                            {
                                orgId = orgInfo.id;
                            }
                        }
                    }
                    if (_treeType == 5)
                    {
                        orgId = (long)cameraInfo.ORG_ID.Value;
                    }
                }

                if (orgId > 0)
                {
                    if (dictCameraCount.ContainsKey(orgId))
                    {
                        dictCameraCount[orgId]++;
                    }
                    else
                    {
                        dictCameraCount.Add(orgId, 1);
                    }
                    PtOrgInfo orgInfo;
                    if (dictOrgListAll.TryGetValue(orgId, out orgInfo))
                    {
                        action(orgInfo, dictCameraCount);
                    }
                }

                if (orgId > 0 && cameraInfo.CAMERA_STATE == "1")
                {
                    if (dictOnlineCameraCount.ContainsKey(orgId))
                    {
                        dictOnlineCameraCount[orgId]++;
                    }
                    else
                    {
                        dictOnlineCameraCount.Add(orgId, 1);
                    }
                    PtOrgInfo orgInfo;
                    if (dictOrgListAll.TryGetValue(orgId, out orgInfo))
                    {
                        action(orgInfo, dictOnlineCameraCount);
                    }
                }
            }
        }

        #endregion 计算所有组织机构下的像机数

        // ==== 按钮事件 ================================================================================================

        #region btnReloadTree_Click 重新生成树
        private void btnReloadTree_Click(object sender, RoutedEventArgs e)
        {
            ShowOrgCameraTree();
        }
        #endregion

        #region btnSelectedCameras_Click 获取选择的摄像机集合
        private void btnSelectedCameras_Click(object sender, RoutedEventArgs e)
        {
            DateTime dt = DateTime.Now;
            List<PtCameraInfo> list = this.orgTree.GetSelectedCameras();
            if (list.Count > 0)
            {
                StringBuilder sbCameras = new StringBuilder();
                list.ForEach(item =>
                {
                    sbCameras.Append("" + item.CAMERA_NAME);
                });
                Log(sbCameras.ToString(1, sbCameras.Length - 1));
                string timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
                Log("选择的摄像机总数:" + list.Count);
                Log("获取选择的摄像机集合耗时:" + timeStr + " 秒\r\n");
            }
            else
            {
                Log("选择的摄像机总数:" + list.Count);
            }
        }
        #endregion

        #region btnSelectedOrgs_Click 获取选择的组织机构集合
        private void btnSelectedOrgs_Click(object sender, RoutedEventArgs e)
        {
            DateTime dt = DateTime.Now;
            List<PtOrgInfo> list = this.orgTree.GetSelectedOrgs();
            if (list.Count > 0)
            {
                StringBuilder sbCameras = new StringBuilder();
                list.ForEach(item =>
                {
                    sbCameras.Append("" + item.orgName);
                });
                Log(sbCameras.ToString(1, sbCameras.Length - 1));
                string timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
                Log("选择的组织机构总数:" + list.Count);
                Log("获取选择的组织机构集合耗时:" + timeStr + " 秒\r\n");
            }
            else
            {
                Log("选择的组织机构总数:" + list.Count);
            }
        }
        #endregion

        #region btnSearch_Click 搜索
        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            DateTime dt = DateTime.Now;
            this.orgTree.Search(txtSearchKey.Text.Trim());
            SetCameraCount(orgNodeDataListFlat, orgListAll, cameraNodeDataList); //设置摄像机在离线数量
            string timeStr = DateTime.Now.Subtract(dt).TotalSeconds.ToString("0.000");
            Log("搜索耗时:" + timeStr + "");
        }
        #endregion

        #region btnReloadTree_Click 重新生成树(较大数据量)
        private void btnReloadTreeBigData_Click(object sender, RoutedEventArgs e)
        {
            ShowOrgCameraTree(true);
        }
        #endregion

    }
}
View Code

效果图:

效果图2:

效果图3:

 

   

文章来源:https://www.cnblogs.com/s0611163/p/15770212.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:如何提升.NET控制台应用体验?
下一篇:分享一个自研开发的QA自动化审计工具-Sonar检查
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

WPF 组织机构摄像机 数据 摄像机节点
百亿级数据 分库表 后怎么查询?
.NET中大型项目开发必备(8)--高效
[WPF] 实现两个任天堂 Switch 的动画
百亿级数据 分库表 后怎么查询?
ABAP基础语法:变、系统变数据类型与结构体变量详解
C# 解析读取XML文件的正确姿势
.Net 下高性能表分库组件-连接模式原理
从数据库或者其他位置ASP.NET MVC Views 视图 数据库中加 cshtml
SAP S/4HANA MM模块培训 32 - MM组织结构定制:公司代码、工厂与采购组织
.NET 百万级 数据插入、更新 ,支持多种数据库
使用.NET 6开发TodoList应用(13)——实现查询
IIS初始化(预),解决第一次访问慢,程序池被回收问题
EF SQL2008 报错 Featch Next
MEF会缺少一些dll,
java项目集成nacos,实现配置以及服务子发现
System.BadImageFormatException:“未能文件或程序集 或它的某一个依赖项。试图格式不正确的程序
SAP S/4HANA 实操 04:MM 基于 Garson 组织架构创建物料主数据并递进练习
不同页面之间通讯交互数据;明细保存后刷新A页面数据
Devexpress 表格GridView列RepositoryItemPictureEdit异步远程URL图片

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划 容差配置 SAP事务码 SAP基础 TCODE Basis 事务代码 MMNR 编号区间 采购实操 组织架构 OMSF SAP实操 FI配置 端口修改 密码设置 数据库配置 远程访问 ABAP基础 SAP ABAP 内表 变量定义 常量 数据类型 ABAP SAP开发 变量 基础语法 系统变量 结构体 字符串处理 循环语句 控制语句 DDIC SE11 数据字典 透明表 ABAP开发 ALE EDI IDoc 增强技术 ABAP内表 HASHED TABLE SORTED TABLE STANDARD TABLE 基本概念 性能优化 PARAMETERS SELECT-OPTIONS SELECTION-SCREEN 报表程序 选择屏幕 F4帮助 Report事件 输入校验 ABAP SQL ABAP语法 Open SQL SELECT 数据库访问 IKuai IP修改 PVE 网络配置 虚拟化
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码