前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WPF TreeGrid MVVM 模式下自定义表格带展开缩放效果,并且可以获取点击行的数据

WPF TreeGrid MVVM 模式下自定义表格带展开缩放效果,并且可以获取点击行的数据

作者头像
Shunnet
发布2022-05-31 10:32:57
5.2K0
发布2022-05-31 10:32:57
举报
文章被收录于专栏:一路走一路失去也一路拥有

先来简单的了解下什么是MVVM模式

简单官解如下:

MVVM其实就是:Model 、View、ViewModel三个的简称,就像MVC一样。 Model就是模型。View就是视图。ViewModel就是和view进行绑定的。

我的理解就是:

就是前后端分离,通过数据绑定或双向绑定的形式来更新界面

切入正题,怎么用MVVM实现[自定义表格带展开缩放效果,并且可以获取点击行的数据,还可以单独更新某列或行数据]

先来看一下界面

只做了一级节点,对于我工作项目来说,一级节点够用了,需要整多级节点的,可以联系我,也可以自己研究

接下来就直接上代码,源码请滑至最下面,自行下载

【前端标红的代码得特别注意哦】

主界面前端代码

【Demo.xaml】

代码语言:javascript
复制
<Window x:Class="TreeGridDemo.Demo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local1="clr-namespace:TreeGridDemo" 
        xmlns:local2="clr-namespace:TreeGridDemo.MvvmHelper" 
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d"
        Background="#F6F8F8"
        Title="www.shunnet.top" Height="780" Width="977" Name="Demonstration">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="DemoStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <!--传递多个参数-->
        <Button Grid.Row="0" Command="{Binding StartDataUpdate}" Content="启动数据更新" FontSize="20" FontWeight="Bold" Name="BtnGO">
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource ResourceKey=MultiValueConverter}" Mode="TwoWay">
                    <MultiBinding.Bindings>
                        <!--把表格对象传给后台-->
                        <Binding ElementName="TreeGridList"/>
                        <Binding ElementName="Demonstration"/>
                        <!--也可以传递自身-->
                        <Binding ElementName="BtnGO"/>
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
        <!--表格显示-->
        <TreeView Grid.Row="1" Name="TreeGridList" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderBrush="#D5DFE5" Margin="0" BorderThickness="0" VerticalAlignment="Top" Background="Transparent"   ItemsSource="{Binding TreeGridDataStructures}" >
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="PreviewMouseUp">
                    <local2:EventCommand Command="{Binding PreviewMouseUp}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <TreeView.ItemTemplate >
                <HierarchicalDataTemplate DataType="{x:Type local1:TreeGridDataStructure}" ItemsSource="{Binding Children}" >
                    <Border CornerRadius="0" Margin="1"  x:Name="back" MinWidth="70" Background="Transparent" DataContext="{Binding}">
                        <StackPanel Orientation="Horizontal" Margin="0,15,0,0">
                            <TextBlock Text="{Binding Text}" />
                        </StackPanel>
                    </Border>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>

主界面后端代码

【Demo.xaml.cs】  

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

namespace TreeGridDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class Demo : Window
    {
        public Demo()
        {
            InitializeComponent();
            this.DataContext = new Controller(this);
        }
    }
}

样式代码,也就是WPF资源字典,后坠.xaml

【DemoStyle.xaml】

代码语言:javascript
复制
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local1="clr-namespace:TreeGridDemo"
                    xmlns:local2="clr-namespace:TreeGridDemo.MvvmHelper"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">

    <Style x:Key="ButtonImageStyle" TargetType="{x:Type Image}">
        <Setter Property="Stretch" Value="Fill"/>
        <Setter Property="Margin" Value="0,0,5,0"/>
        <Setter Property="Width" Value="20"/>
        <Setter Property="Height" Value="20"/>
    </Style>
    <Style x:Key="ButtonTextBlockStyle" TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
    </Style>

    <Style x:Key="ExpandCollapseToggleStyle"
           TargetType="{x:Type ToggleButton}">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="Width" Value="19"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Width="19"
                    Height="13"
                    Background="Transparent">
                        <Border Width="9"
                      Height="9"
                      BorderThickness="1"
                      BorderBrush="#FF7898B5"
                      CornerRadius="1"
                      SnapsToDevicePixels="true">
                            <Border.Background>
                                <LinearGradientBrush StartPoint="0,0"
                                       EndPoint="1,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStop Color="White"
                                    Offset=".2"/>
                                        <GradientStop Color="#FFC0B7A6"
                                    Offset="1"/>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Border.Background>
                            <Path x:Name="ExpandPath"
                      Margin="1,1,1,1"
                      Fill="Black"
                      Data="M 0 2 L 0 3 L 2 3 L 2 5 L 3 5 L 3 3 
                            L 5 3 L 5 2 L 3 2 L 3 0 L 2 0 L 2 2 Z"/>
                        </Border>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Data" TargetName="ExpandPath" Value="M 0 2 L 0 3 L 5 3 L 5 2 Z"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <DataTemplate x:Key="CellTemplate_Name">
        <DockPanel>
            <ToggleButton x:Name="Expander" 
                          Style="{StaticResource ExpandCollapseToggleStyle}"   
                          IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}"
                          ClickMode="Press"/>
        </DockPanel>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=HasItems, RelativeSource={RelativeSource  AncestorType={x:Type TreeViewItem}}}"  Value="false" >
                <Setter TargetName="Expander" Property="Visibility" Value="Hidden" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
    <GridViewColumnCollection x:Key="gvcc" >
        <GridViewColumn  CellTemplate="{StaticResource CellTemplate_Name}" Width="44"/>
        <GridViewColumn DisplayMemberBinding="{Binding Index1}"  Width="160">
            <GridViewColumn.Header>
                <StackPanel Orientation="Horizontal" >
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"  FontSize="18" FontWeight="Bold" Foreground="Black">ID</TextBlock>
                </StackPanel>
            </GridViewColumn.Header>
        </GridViewColumn>
        <GridViewColumn  DisplayMemberBinding="{Binding Index2}"  Width="200">
            <GridViewColumn.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"  FontSize="18" FontWeight="Bold" Foreground="Black">Name</TextBlock>
                </StackPanel>
            </GridViewColumn.Header>
        </GridViewColumn>
        <GridViewColumn DisplayMemberBinding="{Binding Index3}"  Width="310">
            <GridViewColumn.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"  FontSize="18" FontWeight="Bold" Foreground="Black">Value</TextBlock>
                </StackPanel>
            </GridViewColumn.Header>
        </GridViewColumn>
        <GridViewColumn DisplayMemberBinding="{Binding Index4}" Width="200">
            <GridViewColumn.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"  FontSize="18" FontWeight="Bold" Foreground="Black">Set</TextBlock>
                </StackPanel>
            </GridViewColumn.Header>
        </GridViewColumn>
        <GridViewColumn>
            <GridViewColumn.Header>
                <StackPanel Orientation="Horizontal">
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"  FontSize="50" />
                </StackPanel>
            </GridViewColumn.Header>
        </GridViewColumn>
    </GridViewColumnCollection>

    <!-- 悬停状态的画刷 -->
    <SolidColorBrush x:Key="HoverBackgroundBrushKey" Color="#E5F3FB" />
    <SolidColorBrush x:Key="HoverBorderBrushKey" Color="#70C0E7" />

    <!-- 选中(激活)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedActiveBackgroundBrushKey" Color="#CBE8F6" />
    <SolidColorBrush x:Key="SelectedActiveBorderBrushKey" Color="#26A0DA" />

    <!-- 选中(悬停)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedHoverBackgroundBrushKey" Color="#D1E8FF" />
    <SolidColorBrush x:Key="SelectedHoverBorderBrushKey" Color="#66A7E8" />

    <!-- 选中(失效)状态的画刷 -->
    <SolidColorBrush x:Key="SelectedInactiveBackgroundBrushKey" Color="#F7F7F7" />
    <SolidColorBrush x:Key="SelectedInactiveBorderBrushKey" Color="#DEDEDE" />


    <local2:MultiValueConverter x:Key="MultiValueConverter" />
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="Width" Value="auto"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <StackPanel>
                        <Border Name="Border" 
                                Background="{TemplateBinding Background}" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}" 
                                Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                            <Grid Height="{Binding LineHeight}"  local1:GridHelper.ShowBorder="True" Margin="3,0,0,0">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="41"/>
                                    <ColumnDefinition Width="160"/>
                                    <ColumnDefinition Width="200"/>
                                    <ColumnDefinition Width="310"/>
                                    <ColumnDefinition Width="204"/>
                                </Grid.ColumnDefinitions>
                                <!--指示图标-->
                                <Grid Grid.Column="0" VerticalAlignment="Center" >
                                    <ToggleButton x:Name="Expander" 
                                                                      Style="{StaticResource ExpandCollapseToggleStyle}"   
                                                                      IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}}"
                                                                      ClickMode="Press"/>
                                </Grid>
                                <!--信息-->
                                <Grid Grid.Column="1" VerticalAlignment="Center">
                                    <Label  HorizontalAlignment="Center">
                                        <Label.Content>
                                            <TextBlock   Text="{Binding Index1}" FontSize="{Binding FontSize}" FontWeight="{Binding FontWeight}" Foreground="{Binding Foreground}" />
                                        </Label.Content>
                                    </Label>
                                </Grid>
                                <!--信息-->
                                <Grid Grid.Column="2" VerticalAlignment="Center" >
                                    <Label  HorizontalAlignment="Center">
                                        <Label.Content>
                                            <TextBlock Text="{Binding Index2}" FontSize="{Binding FontSize}" FontWeight="{Binding FontWeight}" Foreground="{Binding Foreground}" />
                                        </Label.Content>
                                    </Label>
                                </Grid>
                                <!--控件   与    标签-->
                                <Grid Grid.Column="3" VerticalAlignment="Center" >
                                    <Grid Visibility="{Binding Visibility_String}" >
                                        <Label HorizontalAlignment="Center" VerticalAlignment="Center">
                                            <Label.Content>
                                                <TextBlock Text="{Binding Index3}" FontSize="{Binding FontSize}" FontWeight="{Binding FontWeight}" Foreground="{Binding Foreground}" />
                                            </Label.Content>
                                        </Label>
                                    </Grid>
                                    <Grid Visibility="{Binding Visibility_DataControl}" >
                                        <local1:DynamicData  Minimum="{Binding Minimum}" Maximum="{Binding Maximum}"  Value="{Binding Index3_DataControl}"  SilderWidth="300"  VerticalAlignment="Center" HorizontalAlignment="Center"/>
                                    </Grid>
                                </Grid>
                                <!--控件-->
                                <Grid Grid.Column="4" Visibility="{Binding Visibility_SetButton}"  >
                                    <Button  Width="Auto" Height="{Binding ButtonHeight}" >
                                        <i:Interaction.Triggers>
                                            <i:EventTrigger EventName="Click">
                                                <local2:EventCommand Command="{Binding Click}"/>
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseEnter">
                                                <local2:EventCommand Command="{Binding MouseEnter}"/>
                                            </i:EventTrigger>
                                        </i:Interaction.Triggers>
                                        <StackPanel Orientation="Horizontal">
                                            <Image Source="Image/Set.png" Style="{StaticResource ButtonImageStyle}" />
                                            <TextBlock Text="设置" FontSize="15" FontWeight="Bold" FontFamily="微软雅黑"  HorizontalAlignment="Center"  Style="{StaticResource ButtonTextBlockStyle}" />
                                        </StackPanel>
                                    </Button>
                                </Grid>
                            </Grid>
                        </Border>
                        <ItemsPresenter x:Name="ItemsHost"/>
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Border" Property="BorderBrush"
									Value="{StaticResource SelectedActiveBorderBrushKey}" />
                            <Setter TargetName="Border" Property="Background"
									Value="{StaticResource SelectedActiveBackgroundBrushKey}" />
                        </Trigger>
                        <Trigger Property="HasItems" Value="false">
                            <Setter TargetName="Expander" Property="Visibility" Value="Hidden" />
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="True" />
                                <Condition Property="Selector.IsSelectionActive" Value="False" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Border" Property="BorderBrush"
									Value="{StaticResource SelectedInactiveBorderBrushKey}" />
                            <Setter TargetName="Border" Property="Background"
									Value="{StaticResource SelectedInactiveBackgroundBrushKey}" />
                        </MultiTrigger>
                        <Trigger SourceName="Border" Property="IsMouseOver" Value="True">
                            <Setter TargetName="Border" Property="BorderBrush"
									Value="{StaticResource HoverBorderBrushKey}" />
                            <Setter TargetName="Border" Property="Background"
									Value="{StaticResource HoverBackgroundBrushKey}" />
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="True" />
                                <Condition SourceName="Border" Property="IsMouseOver" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Border" Property="BorderBrush"
									Value="{StaticResource SelectedHoverBorderBrushKey}" />
                            <Setter TargetName="Border" Property="Background"
									Value="{StaticResource SelectedHoverBackgroundBrushKey}" />
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Foreground" 
									Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type TreeView}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeView}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}">
                        <DockPanel>
                            <GridViewHeaderRowPresenter Columns="{StaticResource gvcc}"  DockPanel.Dock="Top" AllowsColumnReorder="False" IsEnabled="False"/>
                            <!--滚动条-->
                            <ScrollViewer Height="{Binding TreeGridHeight}" VerticalScrollBarVisibility="Auto"  >
                                <ItemsPresenter HorizontalAlignment="Left"/>
                            </ScrollViewer>
                        </DockPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>



    <!-- 滚动条滑块 -->
    <Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Grid>
                        <!--滚动条滑块颜色-->
                        <Border Background="#FF898989" CornerRadius="3"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 滚动条滑块上下空白区域 -->
    <Style x:Key="VerticalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Opacity" Value="0.2"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Rectangle Fill="{TemplateBinding Background}" 
                               Width="{TemplateBinding Width}" 
                               Height="{TemplateBinding Height}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 滚动条滑块左右空白区域 -->
    <Style x:Key="HorizontalScrollBarPageButton" TargetType="{x:Type RepeatButton}">
        <Setter Property="OverridesDefaultStyle" Value="true"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Opacity" Value="0.2"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Rectangle Fill="{TemplateBinding Background}" 
                               Width="{TemplateBinding Width}" 
                               Height="{TemplateBinding Height}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 滚动条上下按钮 -->
    <Style x:Key="VerticalScrollBarPageButton2" TargetType="{x:Type RepeatButton}">
        <Setter Property="OverridesDefaultStyle"  Value="true"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="IsTabStop" Value="false"/>
        <Setter Property="Opacity"  Value="0.2"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type RepeatButton}">
                    <Rectangle Fill="#90000000" Width="0" Height="0"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- 滚动条完整 -->
    <Style x:Key="for_scrollbar" TargetType="{x:Type ScrollBar}">
        <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="false"/>
        <Setter Property="Margin" Value="0,2,0,2"/>
        <Setter Property="Width" Value="6"/>
        <Setter Property="MinWidth" Value="6"/>
        <Setter Property="Opacity" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ScrollBar}">
                    <Grid x:Name="Bg" SnapsToDevicePixels="true">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"></RowDefinition>
                            <RowDefinition Height="*"></RowDefinition>
                            <RowDefinition Height="auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <RepeatButton  Grid.Row="0" Style="{DynamicResource VerticalScrollBarPageButton2}" Command="{x:Static ScrollBar.PageUpCommand}"/>
                        <Track x:Name="PART_Track"   Grid.Row="1" IsEnabled="{TemplateBinding IsMouseOver}" IsDirectionReversed="true">
                            <Track.DecreaseRepeatButton>
                                <RepeatButton Style="{DynamicResource VerticalScrollBarPageButton}" Command="{x:Static ScrollBar.PageUpCommand}"/>
                            </Track.DecreaseRepeatButton>
                            <Track.IncreaseRepeatButton>
                                <RepeatButton Style="{DynamicResource VerticalScrollBarPageButton}" Command="{x:Static ScrollBar.PageDownCommand}"/>
                            </Track.IncreaseRepeatButton>
                            <Track.Thumb>
                                <Thumb Style="{DynamicResource ScrollBarThumb}"/>
                            </Track.Thumb>
                        </Track>
                        <RepeatButton Grid.Row="2" Style="{DynamicResource VerticalScrollBarPageButton2}" Command="{x:Static ScrollBar.PageDownCommand}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="Orientation" Value="Horizontal">
                <Setter Property="Background"  Value="Transparent"/>
                <Setter Property="Margin" Value="2,0,2,0"/>
                <Setter Property="Height"   Value="6"/>
                <Setter Property="MinHeight"  Value="6"/>
                <Setter Property="Width"    Value="Auto"/>
                <Setter Property="Opacity" Value="1"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ScrollBar}">
                            <Grid x:Name="Bg" SnapsToDevicePixels="true">
                                <Track x:Name="PART_Track" IsEnabled="{TemplateBinding IsMouseOver}">
                                    <Track.DecreaseRepeatButton>
                                        <RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}"  Command="{x:Static ScrollBar.PageLeftCommand}"/>
                                    </Track.DecreaseRepeatButton>
                                    <Track.IncreaseRepeatButton>
                                        <RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}"  Command="{x:Static ScrollBar.PageRightCommand}"/>
                                    </Track.IncreaseRepeatButton>
                                    <Track.Thumb>
                                        <Thumb Style="{StaticResource ScrollBarThumb}"/>
                                    </Track.Thumb>
                                </Track>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

    <!-- 滚动条 -->
    <Style TargetType="{x:Type ScrollViewer}">
        <Setter Property="BorderBrush"  
                Value="LightGray"/>
        <Setter Property="BorderThickness"  
                Value="0"/>
        <Setter Property="HorizontalContentAlignment"  
                Value="Left"/>
        <Setter Property="HorizontalScrollBarVisibility"  
                Value="Disabled"/>
        <Setter Property="VerticalContentAlignment"  
                Value="Top"/>
        <Setter Property="VerticalScrollBarVisibility"  
                Value="Visible"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                    <Border BorderBrush="{TemplateBinding BorderBrush}"  
                            BorderThickness="{TemplateBinding BorderThickness}"  
                            SnapsToDevicePixels="True">
                        <Grid Background="{TemplateBinding Background}">
                            <ScrollContentPresenter  
                                Cursor="{TemplateBinding Cursor}"  
                                Margin="{TemplateBinding Padding}"  
                                ContentTemplate="{TemplateBinding ContentTemplate}"/>
                            <!--垂直滚动条-->
                            <ScrollBar x:Name="PART_VerticalScrollBar"  
                                       HorizontalAlignment="Right"  
                                       Maximum="{TemplateBinding ScrollableHeight}"  
                                       Orientation="Vertical"  
                                       Style="{StaticResource for_scrollbar}"  
                                       ViewportSize="{TemplateBinding ViewportHeight}"  
                                       Value="{TemplateBinding VerticalOffset}"  
                                       Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
                            <!--水平滚动条-->
                            <ScrollBar x:Name="PART_HorizontalScrollBar"  
                                       Maximum="{TemplateBinding ScrollableWidth}"  
                                       Orientation="Horizontal"  
                                       Style="{StaticResource for_scrollbar}"  
                                       VerticalAlignment="Bottom"  
                                       Value="{TemplateBinding HorizontalOffset}"  
                                       ViewportSize="{TemplateBinding ViewportWidth}"  
                                       Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <EventTrigger RoutedEvent="ScrollChanged">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_VerticalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="1"  
                                        Duration="0:0:1"/>
                                    <!--自动消失-->
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_VerticalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="0"  
                                        Duration="0:0:1"  
                                        BeginTime="0:0:1"/>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_HorizontalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="1"  
                                        Duration="0:0:1"/>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_HorizontalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="0"  
                                        Duration="0:0:1"  
                                        BeginTime="0:0:1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                        <EventTrigger RoutedEvent="MouseEnter"  
                                      SourceName="PART_VerticalScrollBar">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_VerticalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="1"  
                                        Duration="0:0:1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                        <!---鼠标离开后渐渐消失-->

                        <EventTrigger RoutedEvent="MouseLeave"  
                                      SourceName="PART_VerticalScrollBar">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_VerticalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="0"  
                                        Duration="0:0:1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>

                        <EventTrigger RoutedEvent="MouseEnter"  
                                      SourceName="PART_HorizontalScrollBar">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_HorizontalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="1"  
                                        Duration="0:0:1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                        <EventTrigger RoutedEvent="MouseLeave"  
                                      SourceName="PART_HorizontalScrollBar">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation  
                                        Storyboard.TargetName="PART_HorizontalScrollBar"  
                                        Storyboard.TargetProperty="Opacity"  
                                        To="0"  
                                        Duration="0:0:1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

ViewModel代码

【Controller.cs】

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using TreeGridDemo.MvvmHelper;
namespace TreeGridDemo
{
    /// <summary>
    /// 控制器- 也就是VIEWMODEL    我不是按标准的MVVM来命名   这样我习惯这样了  还可以分很多,有业务处理可以建立个解决方案或者类来处理业务   在这个VIMEWMODEL 中使用业务处理的函数,编程这东西转过来转过去也就那样
    /// </summary>
    public class Controller : NotifyObject
    {
        public Controller(FrameworkElement frameworkElement)
        {
            frameworkElement.Loaded += FrameworkElement_Loaded;
        }

        //窗体加载完成
        private void FrameworkElement_Loaded(object sender, RoutedEventArgs e)
        {
            //创建显示数据
            #region 测试数据
            //测试数据
            TreeGridDataStructure One1 = new TreeGridDataStructure()
            {
                LineHeight = 40,
                FontSize = 15,
                FontWeight = FontWeight.FromOpenTypeWeight(999),
                Visibility_String = Visibility.Visible,
                Foreground = new SolidColorBrush((System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#575757")),
                Visibility_SetButton = Visibility.Visible,
                Index1 = "68",
                Index2 = "【☆】",
                Index3 = (new Random().Next(100000000, 999999999)).ToString(),
            };
            One1.Children.Add(new TreeGridDataStructure()
            {
                Visibility_String = Visibility.Visible,
                Index1 = One1.Index1 + "/1",
                Index2 = "☆运行时间",
                Index3 = "18小时"
            });
            One1.Children.Add(new TreeGridDataStructure()
            {
                Visibility_DataControl = Visibility.Visible,
                Index1 = One1.Index1 + "/2",
                Index2 = "☆当前速值",
                Maximum = 100,
                Minimum = -100
            }); ;
            One1.Children.Add(new TreeGridDataStructure()
            {
                Visibility_DataControl = Visibility.Visible,
                Index1 = One1.Index1 + "/2",
                Index2 = "☆当前力值",
                Maximum = 60,
                Minimum = -60
            });
            TreeGridDataStructures.Add(One1);
            //测试数据
            TreeGridDataStructure One2 = new TreeGridDataStructure()
            {
                LineHeight = 40,
                FontSize = 15,
                FontWeight = FontWeight.FromOpenTypeWeight(999),
                Visibility_String = Visibility.Visible,
                Foreground = new SolidColorBrush((System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#575757")),
                Visibility_SetButton = Visibility.Visible,
                Index1 = "69",
                Index2 = "【★】",
                Index3 = (new Random().Next(100000000, 999999999)).ToString()
            };

            for (int i = 1; i <= 10; i++)
            {
                One2.Children.Add(new TreeGridDataStructure()
                {
                    Visibility_DataControl = Visibility.Visible,
                    Index1 = One2.Index1 + "/" + i.ToString(),
                    Index2 = $"★{i}当前气值",
                    Maximum = 40,
                    Minimum = -40
                });
                Thread.Sleep(1);
            }
            TreeGridDataStructures.Add(One2);


            //只绑定父节点的按钮点击事件
            //子节点有表格点击事件呈现

            //如果子节点绑定了按钮   默认会触发表格的点击事件   因为表格在最上层  而按钮在表格下面 只会触发最上层的事件
            foreach (var item in TreeGridDataStructures)
            {
                item.SetButtonClick += SetButtonClick;
            }


            #endregion
        }


        #region 私有字段
        private ObservableCollection<TreeGridDataStructure> _TreeGridDataStructures;
        private Command<MouseButtonEventArgs> _PreviewMouseUp;
        private Command _StartDataUpdate;
        #endregion

        /// <summary>
        /// 按钮点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void SetButtonClick(object sender, RoutedEventArgs e)
        {
            TreeGridDataStructure Data = sender as TreeGridDataStructure; //得到数据
            MessageBox.Show($"【设置按钮点击】\r\n你当前点击行为:{(Data.Children.Count > 0 ? "父节点" : "子节点")},数据如下\r\n<{Data.Index1}><{Data.Index2}><{(string.IsNullOrEmpty(Data.Index3) ? Data.Index3_DataControl.ToString() : Data.Index3)}>\r\n{(Data.Children.Count > 0 ? "包含" + Data.Children.Count + "个子节点" : String.Empty)}", "wwww.shunnet.top", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        /// <summary>
        /// 树结构单击数据
        /// </summary>
        public Command<MouseButtonEventArgs> PreviewMouseUp
        {
            get
            {
                if (_PreviewMouseUp == null)
                    _PreviewMouseUp = new Command<MouseButtonEventArgs>(
                        new Action<MouseButtonEventArgs>(e =>
                        {
                            TreeView tv = e.Source as TreeView;
                            if (tv.ItemsSource != null)
                            {
                                TreeGridDataStructure Data = tv.SelectedItem as TreeGridDataStructure;
                                if (Data == null) return;
                                if (Data.Children.Count.Equals(0))
                                {
                                    //得到当前行数据
                                    MessageBox.Show($"【树表格点击】\r\n你当前点击行为:{(Data.Children.Count > 0 ? "父节点" : "子节点")},数据如下\r\n<{Data.Index1}><{Data.Index2}><{(string.IsNullOrEmpty(Data.Index3) ? Data.Index3_DataControl.ToString() : Data.Index3)}>\r\n{(Data.Children.Count > 0 ? "包含" + Data.Children.Count + "个子节点" : String.Empty)}", "wwww.shunnet.top", MessageBoxButton.OK, MessageBoxImage.Information);
                                }
                            }
                        }));
                return _PreviewMouseUp;
            }
        }

        /// <summary>
        /// 树表格结构集合
        /// </summary>
        public ObservableCollection<TreeGridDataStructure> TreeGridDataStructures
        {
            get
            {
                if (_TreeGridDataStructures == null)
                {
                    _TreeGridDataStructures = new ObservableCollection<TreeGridDataStructure>();
                }
                return _TreeGridDataStructures;
            }
            set
            {
                if (value != null)
                {
                    _TreeGridDataStructures = value;
                    RaisePropertyChanged("TreeGridDataStructures");
                }
            }
        }

        /// <summary>
        /// 启动数据更新
        /// </summary>
        public Command StartDataUpdate
        {
            get
            {
                if (_StartDataUpdate == null)
                    _StartDataUpdate = new Command(new Action<object>
                    (
                        o =>
                        {
                            object[] Data = (object[])o;
                            //传递过来的数据
                            //第零位为树形表格对象
                            TreeView treeView = Data[0] as TreeView;
                            //第一位为窗体对象
                            Window window = Data[1] as Window;
                            //第二位是按钮对象
                            Button button = Data[2] as Button;
                            //以上就是参数传递



                            //我们最终目的是让数据控件动起来
                            if (button.Content.Equals("启动数据更新"))
                            {
                                //让数据控件动起来
                                go = true;
                                ThreadPool.QueueUserWorkItem(c => test());
                                button.Content = "停止数据更新";
                                SetNodeExpandedState(treeView, true);   //展开节点
                            }
                            else if (button.Content.Equals("停止数据更新"))
                            {
                                RegularlyCleaned();
                                button.Content = "启动数据更新";
                                SetNodeExpandedState(treeView, false);   //收缩节点
                            }

                        }
                    ));
                return _StartDataUpdate;
            }
        }

        #region 方法

        /// <summary>
        /// WPF TreeView 选中节点的展开与收缩
        /// </summary>
        /// <param name="control">TreeView控件</param>
        /// <param name="treeObj">当不为空只展开此对象节点</param>
        public void SetNodeExpandedState(ItemsControl control, object treeObj)
        {
            try
            {
                if (control != null)
                {
                    foreach (object item in control.Items)
                    {
                        if (treeObj != null)
                        {
                            //使用动态解析,请自行更改属性名
                            dynamic datalist = item;
                            dynamic dataobj = treeObj;
                            if (datalist.Index2.Equals(dataobj.Index2))
                            {
                                TreeViewItem treeItem = control.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;

                                if (treeItem != null && treeItem.HasItems)
                                {
                                    if (treeItem.IsExpanded)//展开或缩放
                                    {
                                        treeItem.IsExpanded = false;
                                    }
                                    else
                                    {
                                        treeItem.IsExpanded = true;
                                    }
                                    if (treeItem.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
                                    {
                                        treeItem.UpdateLayout();
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"节点的展开与收缩异常:{ex.ToString()}");
            }
        }
        /// <summary>
        /// WPF TreeView 所有节点的展开与收缩
        /// </summary>
        /// <param name="control">TreeView控件</param>
        /// <param name="expandNode">true:展开 false:收缩</param>
        public void SetNodeExpandedState(ItemsControl control, bool expandNode)
        {
            try
            {
                if (control != null)
                {
                    foreach (object item in control.Items)
                    {
                        TreeViewItem treeItem = control.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
                      
                        if (treeItem != null && treeItem.HasItems)
                        {
                            treeItem.IsExpanded = expandNode;  //展开或缩放
                            if (treeItem.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
                            {
                                treeItem.UpdateLayout();
                            }
                            SetNodeExpandedState(treeItem as ItemsControl, expandNode);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"节点的展开与收缩异常:{ex.ToString()}");
            }
        }


        bool go = true;

        public void test()
        {
            while (go)
            {
                for (int i = 0; i < TreeGridDataStructures.Count; i++)
                {
                    if (TreeGridDataStructures[i].Children.Count > 0)
                    {
                        for (int ic = 0; ic < TreeGridDataStructures[i].Children.Count; ic++)
                        {
                            if (!go)
                            { return; }
                            TreeGridDataStructures[i].Children[ic].Index3_DataControl += (float)new Random().NextDouble();
                            if (TreeGridDataStructures[i].Children[ic].Index3_DataControl > TreeGridDataStructures[i].Children[ic].Maximum)
                            {
                                TreeGridDataStructures[i].Children[ic].Index3_DataControl = TreeGridDataStructures[i].Children[ic].Minimum;
                            }
                            Thread.Sleep(1);
                        }
                        if (!go)
                        { return; }
                    }
                }
                if (!go)
                { return; }
            }
        }
        /// <summary>
        /// 清理
        /// </summary>
        public void RegularlyCleaned()
        {
            go = false;
            ClearMemory();
        }

        [DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")]
        public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
        /// <summary>
        /// 释放内存
        /// </summary>
        public static void ClearMemory()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
            }
        }
        #endregion


    }
    /// <summary>
    /// 树型表格数据结构  可以更新单条数据
    /// </summary>
    public class TreeGridDataStructure : NotifyObject
    {
        #region 私有字段
        private Command<RoutedEventArgs> _Click;
        private int _LineHeight = 35;
        private Visibility _Visibility_DataControl = Visibility.Hidden;
        private Visibility _Visibility_String = Visibility.Hidden;
        private Visibility _Visibility_SetButton = Visibility.Hidden;
        private SolidColorBrush _Foreground = new SolidColorBrush((System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString("#999696"));
        private FontWeight _FontWeight;
        private double _FontSize = 13;
        private string _Index1;
        private string _Index2;
        private string _Index3;
        private float _Index3_DataControl;
        private int _Maximum;
        private int _Minimum;
        private Command<MouseEventArgs> _MouseDown;
        #endregion
        /// <summary>
        /// 按钮高度
        /// </summary>
        public int ButtonHeight
        {
            get
            {
                return LineHeight - 2;
            }
        }
        /// <summary>
        /// 设置按钮被点击事件
        /// </summary>
        public event EventHandler<RoutedEventArgs> SetButtonClick;
        /// <summary>
        /// 设置按钮被点击
        /// </summary>
        public Command<RoutedEventArgs> Click
        {
            get
            {
                if (_Click == null)
                    _Click = new Command<RoutedEventArgs>(
                        new Action<RoutedEventArgs>(e =>
                        {
                            if (SetButtonClick != null)
                            {
                                SetButtonClick(this, e); //触发事件
                            }
                        }));
                return _Click;
            }
        }
        /// <summary>
        /// 鼠标指标进入元素的界限时发生。
        /// </summary>
        public Command<MouseEventArgs> MouseEnter
        {
            get
            {
                if (_MouseDown == null)
                    _MouseDown = new Command<MouseEventArgs>(
                        new Action<MouseEventArgs>(e =>
                        {
                            var treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;  //让其选中
                            if (treeViewItem != null)
                            {
                                treeViewItem.Focus();
                                e.Handled = true;
                            }
                        }));
                return _MouseDown;
            }
        }

        /// <summary>
        /// 让其选中
        /// </summary>
        /// <returns></returns>
        public DependencyObject VisualUpwardSearch<T>(DependencyObject source)
        {
            while (source != null && source.GetType() != typeof(T))
                source = VisualTreeHelper.GetParent(source);
            return source;
        }

        /// <summary>
        /// 此行的-行高
        /// </summary>
        public int LineHeight
        {
            get
            {
                return _LineHeight;
            }
            set
            {
                _LineHeight = value;
                RaisePropertyChanged("LineHeight");
            }
        }
        /// <summary>
        /// 显示数据控件
        /// </summary>
        public Visibility Visibility_DataControl
        {
            get
            {
                return _Visibility_DataControl;
            }
            set
            {
                _Visibility_DataControl = value;
                RaisePropertyChanged("Visibility_DataControl");
            }
        }
        /// <summary>
        /// 显示字符串
        /// </summary>
        public Visibility Visibility_String
        {
            get
            {
                return _Visibility_String;
            }
            set
            {
                _Visibility_String = value;
                RaisePropertyChanged("Visibility_String");
            }
        }
        /// <summary>
        /// 显示设置按钮
        /// </summary>
        public Visibility Visibility_SetButton
        {
            get
            {
                return _Visibility_SetButton;
            }
            set
            {
                _Visibility_SetButton = value;
                RaisePropertyChanged("Visibility_SetButton");
            }
        }
        /// <summary>
        /// 此行字体颜色   
        /// </summary>
        public SolidColorBrush Foreground
        {
            get
            {
                return _Foreground;
            }
            set
            {
                _Foreground = value;
                RaisePropertyChanged("Foreground");
            }
        }
        /// <summary>
        /// 此行字体加粗
        /// </summary>
        public FontWeight FontWeight
        {
            get
            {
                return _FontWeight;
            }
            set
            {
                _FontWeight = value;
                RaisePropertyChanged("FontWeight");
            }
        }

        /// <summary>
        /// 此行字体大小
        /// </summary>
        public double FontSize
        {
            get
            {
                return _FontSize;
            }
            set
            {
                _FontSize = value;
                RaisePropertyChanged("FontSize");
            }
        }

        /// <summary>
        /// 最大值
        /// </summary>
        public int Maximum
        {
            get
            {
                return _Maximum;
            }
            set
            {
                _Maximum = value;
                RaisePropertyChanged("Maximum");
            }
        }
        /// <summary>
        /// 最小值
        /// </summary>
        public int Minimum
        {
            get
            {
                return _Minimum;
            }
            set
            {
                _Minimum = value;
                RaisePropertyChanged("Minimum");
            }
        }

        /*
         因为缩放功能,列的数据没有定死,自己想成啥是啥
         */
        public string Index1
        {
            get
            {
                return _Index1;
            }
            set
            {

                if (!string.IsNullOrEmpty(value) && !value.Equals(_Index1))
                {
                    _Index1 = value;
                    RaisePropertyChanged("Index1");
                }
            }
        }
        public string Index2
        {
            get
            {
                return _Index2;
            }
            set
            {

                if (!string.IsNullOrEmpty(value) && !value.Equals(_Index2))
                {
                    _Index2 = value;
                    RaisePropertyChanged("Index2");
                }
            }
        }
        public string Index3
        {
            get
            {
                return _Index3;
            }
            set
            {

                if (!string.IsNullOrEmpty(value) && !value.Equals(_Index3))
                {
                    _Index3 = value;
                    RaisePropertyChanged("Index3");
                }
            }
        }
        public float Index3_DataControl
        {
            get
            {
                return _Index3_DataControl;
            }
            set
            {
                _Index3_DataControl = value;
                RaisePropertyChanged("Index3_DataControl");
            }
        }
        public List<TreeGridDataStructure> Children { get; set; }
        public TreeGridDataStructure()
        {
            Children = new List<TreeGridDataStructure>();
        }

    }
}

自定义动态数据控件前端代码    

【DynamicData.xaml】

代码语言:javascript
复制
<UserControl x:Class="TreeGridDemo.DynamicData"
             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" 
             xmlns:local="clr-namespace:TreeGridDemo"
              mc:Ignorable="d"  Name="UC_Arrange" Loaded="UC_Arrange_Loaded">
    <UserControl.Resources>
        <SolidColorBrush x:Key="SliderThumb.Static.Foreground" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.MouseOver.Background" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.MouseOver.Border" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Pressed.Background" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Pressed.Border" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Disabled.Background" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Disabled.Border" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Static.Background" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Static.Border" Color="Transparent"/>
        <ControlTemplate x:Key="SliderThumbHorizontalTop" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M 0,6 C0,6 5.5,0 5.5,0 5.5,0 11,6 11,6 11,6 11,18 11,18 11,18 0,18 0,18 0,18 0,6 0,6 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="0" UseLayoutRounding="True" VerticalAlignment="Center"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderThumbHorizontalBottom" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M 0,12 C0,12 5.5,18 5.5,18 5.5,18 11,12 11,12 11,12 11,0 11,0 11,0 0,0 0,0 0,0 0,12 0,12 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <SolidColorBrush x:Key="SliderThumb.Track.Border" Color="Transparent"/>
        <SolidColorBrush x:Key="SliderThumb.Track.Background" Color="Transparent"/>
        <Style x:Key="RepeatButtonTransparent" TargetType="{x:Type RepeatButton}">
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Focusable" Value="false"/>
            <Setter Property="IsTabStop" Value="false"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RepeatButton}">
                        <Rectangle Fill="{TemplateBinding Background}" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <ControlTemplate x:Key="SliderThumbHorizontalDefault" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M 0,0 C0,0 11,0 11,0 11,0 11,18 11,18 11,18 0,18 0,18 0,18 0,0 0,0 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" SnapsToDevicePixels="True" Stroke="{StaticResource SliderThumb.Static.Border}" StrokeThickness="1" UseLayoutRounding="True" VerticalAlignment="Center"/>
                <Ellipse Fill="#DDDDDD" Width="5" Height="5" >
                    <Ellipse.Effect>
                        <DropShadowEffect Color="Black" BlurRadius="10"></DropShadowEffect>
                    </Ellipse.Effect>
                </Ellipse>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderHorizontal" TargetType="{x:Type Slider}">
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="false">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TickBar x:Name="TopTick" Fill="{TemplateBinding Foreground}" Height="1"  Placement="Top" Visibility="Collapsed" />
                    <TickBar x:Name="BottomTick" Fill="{TemplateBinding Foreground}" Height="4" Margin="0,2,0,0" Placement="Bottom" Grid.Row="2" Visibility="Collapsed"/>
                    <Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.Background}" Height="4.0" Margin="5,0" Grid.Row="1" VerticalAlignment="center">
                        <Canvas Margin="-6,-1">
                            <Rectangle x:Name="PART_SelectionRange" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="4.0" Visibility="Hidden"/>
                        </Canvas>
                    </Border>
                    <Track x:Name="PART_Track" Grid.Row="1">
                        <Track.DecreaseRepeatButton>
                            <RepeatButton Background="{TemplateBinding Background}" Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}" Visibility="Hidden"/>
                        </Track.DecreaseRepeatButton>
                        <Track.IncreaseRepeatButton>
                            <RepeatButton Background="{TemplateBinding Foreground}" Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}" />
                        </Track.IncreaseRepeatButton>
                        <Track.Thumb>
                            <Thumb x:Name="Thumb" Focusable="False" Height="18" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbHorizontalDefault}" VerticalAlignment="Center" Width="0"  Visibility="Hidden"/>
                        </Track.Thumb>
                    </Track>
                </Grid>
            </Border>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderThumbVerticalLeft" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M 6,11 C6,11 0,5.5 0,5.5 0,5.5 6,0 6,0 6,0 18,0 18,0 18,0 18,11 18,11 18,11 6,11 6,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderThumbVerticalRight" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M 12,11 C12,11 18,5.5 18,5.5 18,5.5 12,0 12,0 12,0 0,0 0,0 0,0 0,11 0,11 0,11 12,11 12,11 z" Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderThumbVerticalDefault" TargetType="{x:Type Thumb}">
            <Grid HorizontalAlignment="Center" UseLayoutRounding="True" VerticalAlignment="Center">
                <Path x:Name="grip" Data="M0.5,0.5 L18.5,0.5 18.5,11.5 0.5,11.5z" 
                      Fill="{StaticResource SliderThumb.Static.Background}" Stretch="Fill" Stroke="{StaticResource SliderThumb.Static.Border}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.MouseOver.Border}"/>
                </Trigger>
                <Trigger Property="IsDragging" Value="true">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Pressed.Border}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Background}"/>
                    <Setter Property="Stroke" TargetName="grip" Value="{StaticResource SliderThumb.Disabled.Border}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="SliderVertical" TargetType="{x:Type Slider}">
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="false">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition MinWidth="{TemplateBinding MinWidth}" Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TickBar x:Name="TopTick" Grid.Column="0" Fill="{TemplateBinding Foreground}" Margin="0,0,2,0" Placement="Left" Visibility="Collapsed" Width="4"/>
                    <TickBar x:Name="BottomTick" Grid.Column="2" Fill="{TemplateBinding Foreground}" Margin="2,0,0,0" Placement="Right" Visibility="Collapsed" Width="4"/>
                    <Border x:Name="TrackBackground" BorderBrush="{StaticResource SliderThumb.Track.Border}" BorderThickness="1" Background="{StaticResource SliderThumb.Track.Background}" Grid.Column="1" HorizontalAlignment="center" Margin="0,5" Width="4.0">
                        <Canvas Margin="-1,-6">
                            <Rectangle x:Name="PART_SelectionRange" 
                                       Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" 
                                       Visibility="Hidden"
                                       Width="4.0"/>
                        </Canvas>
                    </Border>
                    <Track x:Name="PART_Track" Grid.Column="1">
                        <Track.DecreaseRepeatButton>
                            <RepeatButton Command="{x:Static Slider.DecreaseLarge}" Style="{StaticResource RepeatButtonTransparent}" Visibility="Hidden"/>
                        </Track.DecreaseRepeatButton>
                        <Track.IncreaseRepeatButton>
                            <RepeatButton Command="{x:Static Slider.IncreaseLarge}" Style="{StaticResource RepeatButtonTransparent}" />
                        </Track.IncreaseRepeatButton>
                        <Track.Thumb>
                            <Thumb x:Name="Thumb" Focusable="False" Height="11" OverridesDefaultStyle="True" Template="{StaticResource SliderThumbVerticalDefault}" VerticalAlignment="Top" Width="0"  Visibility="Hidden"/>
                        </Track.Thumb>
                    </Track>
                </Grid>
            </Border>
        </ControlTemplate>
        <Style x:Key="SliderStyle1" TargetType="{x:Type Slider}">
            <Setter Property="Stylus.IsPressAndHoldEnabled" Value="false"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Foreground" Value="{StaticResource SliderThumb.Static.Foreground}"/>
            <Setter Property="Template" Value="{StaticResource SliderHorizontal}"/>
        </Style>
    </UserControl.Resources>
    <StackPanel  Orientation="Horizontal" Height="{Binding ElementName=UC_Arrange,Path=SilderHeight}" >
        <Grid>
            <Canvas Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}"   Height="18">
                <Slider Name="SL_Bat1" VerticalAlignment="Center" HorizontalAlignment="Right" 
                            Value="{Binding ElementName=UC_Arrange,Path=StartValue}"
                            Minimum="{Binding ElementName=UC_Arrange,Path=Minimum}"
                            Maximum="{Binding ElementName=UC_Arrange,Path=Maximum}"
                            SelectionStart="{Binding ElementName=UC_Arrange,Path=StartValue}"
                            SelectionEnd="{Binding ElementName=UC_Arrange,Path=EndValue}"
                            Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}"
                            TickFrequency="{Binding ElementName=UC_Arrange,Path=SliderTickFrequency}"
                            FocusVisualStyle="{x:Null}"
                            IsSelectionRangeEnabled="False"
                            TickPlacement="None" Background="#CAD9C8" Foreground="#27AE60"
                            IsSnapToTickEnabled="False"
                            IsEnabled="False"
                            ValueChanged="SL_Bat1_ValueChanged" Style="{DynamicResource SliderStyle1}">
                    <Slider.Clip>
                        <RectangleGeometry Rect="{Binding ElementName=UC_Arrange,Path=StartRect}" />
                    </Slider.Clip>
                </Slider>
                <Slider Name="SL_Bat2" Background="#27AE60" Foreground="#CAD9C8" Style="{DynamicResource SliderStyle1}" VerticalAlignment="Center"  HorizontalAlignment="Left" 
                            Value="{Binding ElementName=UC_Arrange,Path=EndValue}" 
                            Minimum="{Binding ElementName=UC_Arrange,Path=Minimum}" 
                            Maximum="{Binding ElementName=UC_Arrange,Path=Maximum}" 
                            SelectionStart="{Binding ElementName=UC_Arrange,Path=StartValue}" 
                            SelectionEnd="{Binding ElementName=UC_Arrange,Path=EndValue}" 
                            Width="{Binding ElementName=UC_Arrange,Path=SilderWidth}"
                            TickFrequency="{Binding ElementName=UC_Arrange,Path=SliderTickFrequency}"
                            FocusVisualStyle="{x:Null}"
                            IsSelectionRangeEnabled="False"                
                            TickPlacement="None"
                            IsSnapToTickEnabled="False"
                            IsEnabled="False"
                            ValueChanged="SL_Bat2_ValueChanged">
                    <Slider.Clip>
                        <RectangleGeometry Rect="{Binding ElementName=UC_Arrange,Path=EndRect}" />
                    </Slider.Clip>
                </Slider>
            </Canvas >
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*"/>
                    <ColumnDefinition Width="1*"/>
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0" >
                    <Label HorizontalAlignment="Left" VerticalAlignment="Center" >
                        <Label.Content>
                            <TextBlock Text="{Binding ElementName=SL_Bat1,Path=Minimum}" Foreground="Black" />
                        </Label.Content>
                    </Label>
                </Grid>
                <Grid Grid.Column="1">
                    <Label HorizontalAlignment="Right" VerticalAlignment="Center">
                        <Label.Content>
                            <TextBlock Text="{Binding ElementName=SL_Bat2,Path=Maximum}" Foreground="Black"/>
                        </Label.Content>
                    </Label>
                </Grid>
            </Grid>
            <Grid>
                <Label HorizontalAlignment="Center"   VerticalAlignment="Center" >
                    <Label.Content>
                        <TextBlock Text="{Binding ElementName=UC_Arrange,Path=Value}" Foreground="Black"/>
                    </Label.Content>
                </Label>
            </Grid>
        </Grid>
    </StackPanel>
</UserControl>

自定义动态数据控件后端代码  

【DynamicData.xaml.cs】

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

namespace TreeGridDemo
{
    /// <summary>
    /// DynamicData.xaml 的交互逻辑
    /// </summary>
    public partial class DynamicData : UserControl
    {
        public DynamicData()
        {
            InitializeComponent();
        }
        #region 私有变量

        private static int _width = 150;  // 拖动条初始宽度
        private static int _height = 30;  // 高度
        private static int _min = 0;      // 最小值
        private static int _max = 0;    // 最大值
        private static int _freq = 0;    // 出现刻度的间距

        #endregion
        #region 私有属性

        /// <summary>
        /// 裁剪矩阵(头)
        /// </summary>
        private Rect StartRect
        {
            get { return (Rect)GetValue(StartRectProperty); }
            set
            {
                SetValue(StartRectProperty, value);
            }
        }
        private static readonly DependencyProperty StartRectProperty = DependencyProperty.Register("StartRect", typeof(Rect), typeof(DynamicData));

        /// <summary>
        /// 裁剪矩阵(尾)
        /// </summary>
        private Rect EndRect
        {
            get { return (Rect)GetValue(EndRectProperty); }
            set
            {
                SetValue(EndRectProperty, value);
            }
        }
        private static readonly DependencyProperty EndRectProperty = DependencyProperty.Register("EndRect", typeof(Rect), typeof(DynamicData));

        #endregion

        #region 公开依赖属性

        /// <summary>
        /// 刻度间距,默认为10
        /// </summary>
        public int SliderTickFrequency
        {
            get { return (int)GetValue(SliderTickFrequencyProperty); }
            set { SetValue(SliderTickFrequencyProperty, value); }
        }
        public static readonly DependencyProperty SliderTickFrequencyProperty =
            DependencyProperty.Register("SliderTickFrequency", typeof(int), typeof(DynamicData), new PropertyMetadata(_freq));

        /// <summary>
        /// 控件高度,默认为30
        /// </summary>
        public int SilderHeight
        {
            get { return (int)GetValue(SilderHeightProperty); }
            set { SetValue(SilderHeightProperty, value); }
        }
        public static readonly DependencyProperty SilderHeightProperty =
            DependencyProperty.Register("SilderHeight", typeof(int), typeof(DynamicData), new PropertyMetadata(_height));

        /// <summary>
        /// 拖动条宽度,默认为150
        /// </summary>
        public int SilderWidth
        {
            get { return (int)GetValue(SilderWidthProperty); }
            set { SetValue(SilderWidthProperty, value); }
        }
        public static readonly DependencyProperty SilderWidthProperty =
            DependencyProperty.Register("SilderWidth", typeof(int), typeof(DynamicData), new PropertyMetadata(_width));

        /// <summary>
        /// 最小值,默认为0
        /// </summary>
        public int Minimum
        {
            get { return (int)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }
        public static readonly DependencyProperty MinimumProperty =
            DependencyProperty.Register("Minimum", typeof(int), typeof(DynamicData), new PropertyMetadata(_min));

        /// <summary>
        /// 最大值,默认为100
        /// </summary>
        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }
        public static readonly DependencyProperty MaximumProperty =
            DependencyProperty.Register("Maximum", typeof(int), typeof(DynamicData), new PropertyMetadata(_max));

        /// <summary>
        /// 选中开始值,默认为0
        /// </summary>
        public int StartValue
        {
            get { return (int)GetValue(StartValueProperty); }
            set { SetValue(StartValueProperty, value); }
        }
        public static readonly DependencyProperty StartValueProperty =
            DependencyProperty.Register("StartValue", typeof(int), typeof(DynamicData));
        /// <summary>
        /// 当前值
        /// </summary>
        public float Value
        {
            get
            {
                return (float)GetValue(ValueProperty);
            }
            set
            {
                SetValue(ValueProperty, value);
            }
        }
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(float), typeof(DynamicData), new FrameworkPropertyMetadata(0.00f, FrameworkPropertyMetadataOptions.None, OnValuePropertyChanged));
        private static void OnValuePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            DynamicData dynamicData;
            object newValue;
            if ((dynamicData = dependencyObject as DynamicData) == null || !((newValue = e.NewValue) is float))
            {
                return;
            }
            if ((float)newValue >= 0)
            {
                //正数
                dynamicData.StartValue = 0;
                dynamicData.EndValue = Convert.ToInt32(newValue);
            }
            else
            {
                //负数
                dynamicData.StartValue = Convert.ToInt32(newValue);
                dynamicData.EndValue = 0;
            }
            //RMATool.ClearMemory();
        }
        /// <summary>
        /// 选中结束值,默认为100
        /// </summary>
        public int EndValue
        {
            get { return (int)GetValue(EndValueProperty); }
            set { SetValue(EndValueProperty, value); }
        }
        public static readonly DependencyProperty EndValueProperty =
            DependencyProperty.Register("EndValue", typeof(int), typeof(DynamicData), new PropertyMetadata(_max));

        #endregion

        #region 前台交互

        /// <summary>
        /// 对两个拖动条进行裁剪
        /// </summary>
        private void ClipSilder()
        {
            double selectedValue = EndValue - StartValue;
            double totalValue = Maximum - Minimum;
            double sliderClipWidth = SilderWidth * (StartValue - Minimum + selectedValue / 2) / totalValue;
            if (sliderClipWidth > 0)
            {
                // 对第一个拖动条进行裁剪
                StartRect = new Rect(0, 0, sliderClipWidth, SilderHeight);
                // 对第二个拖动条进行裁剪
                EndRect = new Rect(sliderClipWidth, 0, SilderWidth, SilderHeight);
            }
            else
            {
                selectedValue = StartValue - EndValue;
                totalValue = Minimum - Maximum;
                sliderClipWidth = SilderWidth * (EndValue - Maximum + selectedValue / 2) / totalValue;
                // 对第一个拖动条进行裁剪
                StartRect = new Rect(0, 0, sliderClipWidth, SilderHeight);
                // 对第二个拖动条进行裁剪
                EndRect = new Rect(sliderClipWidth, 0, SilderWidth, SilderHeight);
            }
        }

        /// <summary>
        /// 初始化裁剪
        /// </summary>
        private void UC_Arrange_Loaded(object sender, RoutedEventArgs e)
        {
            ClipSilder();
        }

        private void SL_Bat1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (e.NewValue > EndValue)    // 检查值范围
                StartValue = EndValue;    // 超出,重设为最大值
            ClipSilder();
        }

        private void SL_Bat2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (e.NewValue < StartValue)
                EndValue = StartValue;
            ClipSilder();
        }
        #endregion
    }
}

GRID表格显示边框代码

【GridHelper.cs】

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace TreeGridDemo
{
    /// <summary>
    /// 为Grid添加的一个特殊功能,实线边框
    /// </summary>
    public class GridHelper
    {
        //暂时不处理实时显示的事情
        #region 显示边框信息
        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridHelper)
                , new PropertyMetadata(OnShowBorderChanged));
        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if ((bool)e.OldValue)
                grid.Loaded -= (s, arg) => { };
            else
            {
                grid.Loaded += new RoutedEventHandler(GridLoaded);
            }
        }
        #endregion

        #region 线宽信息
        public static readonly DependencyProperty LineThicknessProperty =
           DependencyProperty.RegisterAttached("LineThickness", typeof(double), typeof(GridHelper),
               new PropertyMetadata(1d, OnGridLineThicknessChanged));
        public static double GetLineThickness(DependencyObject obj)
        {
            return (double)obj.GetValue(LineThicknessProperty);
        }

        public static void SetLineThickness(DependencyObject obj, double value)
        {
            obj.SetValue(LineThicknessProperty, value);
        }


        public static void OnGridLineThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        public static readonly DependencyProperty LineBrushProperty =
            DependencyProperty.RegisterAttached("LineBrush", typeof(Brush), typeof(GridHelper),
                new PropertyMetadata(Brushes.Gray, OnGridLineBrushChanged));

        #region 线画刷问题
        public static Brush GetLineBrush(DependencyObject obj)
        {
            var brush = (Brush)obj.GetValue(LineBrushProperty);
            return new SolidColorBrush((Color)ColorConverter.ConvertFromString("#D5DFE5"));//;?? Brushes.LightGray;//#D5DFE5;
        }

        public static void SetLineBrush(DependencyObject obj, Brush value)
        {
            obj.SetValue(LineBrushProperty, value);
        }

        public static void OnGridLineBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

        }
        #endregion

        private static void GridLoaded(object sender, RoutedEventArgs e)
        {
            #region 思路
            /*
             * 1、覆盖所有单元格都要包围上边框。
             * 2、边框线不能存在重复。每个单元格绘制【右下】部分,主体绘制右上部分
             */
            #endregion
            var grid = sender as Grid;
            var rowCount = Math.Max(1, grid.RowDefinitions.Count);
            var columnCount = Math.Max(1, grid.ColumnDefinitions.Count);
            #region 初始化标准数组
            int[,] flagArray = new int[rowCount, columnCount];
            #endregion
            var controls = grid.Children;
            var count = controls.Count;
            var settingThickness = GetLineThickness(grid);
            var borderBrush = GetLineBrush(grid);
            for (int i = 0; i < count; i++)
            {
                var item = controls[i] as FrameworkElement;
                var row = Grid.GetRow((item));
                var column = Grid.GetColumn(item);
                var rowSpan = Grid.GetRowSpan(item);
                var columnSpan = Grid.GetColumnSpan(item);
                for (int rowTemp = 0; rowTemp < rowSpan; rowTemp++)
                {
                    for (int colTemp = 0; colTemp < columnSpan; colTemp++)
                    {
                        flagArray[rowTemp + row, colTemp + column] = 1;
                    }
                }

                var border = CreateBorder(row, column, rowSpan, columnSpan, settingThickness);
                border.BorderBrush = borderBrush;

                grid.Children.RemoveAt(i);
                border.Child = item;
                grid.Children.Insert(i, border);
            }

            #region 整理为填充单元格
            for (int i = 0; i < rowCount; i++)
            {
                for (int k = 0; k < columnCount; k++)
                {
                    if (flagArray[i, k] == 0)
                    {
                        var border = CreateBorder(i, k, 1, 1, settingThickness);
                        border.BorderBrush = borderBrush;
                        grid.Children.Add(border);
                    }
                }
            }
            #endregion
        }

        private static Border CreateBorder(int row, int column, int rowSpan, int columnSpan, double thickness)
        {
            var useThickness = new Thickness(0, 0, thickness, thickness);
            if (row == 0)
                useThickness.Top = thickness;
            if (column == 0)
                useThickness.Left = thickness;
            var border = new Border()
            {
                BorderThickness = useThickness,
            };
            Grid.SetRow(border, row);
            Grid.SetColumn(border, column);
            Grid.SetRowSpan(border, rowSpan);
            Grid.SetColumnSpan(border, columnSpan);
            return border;
        }
    }
}

还有一些转换器与消息通知的用于MVVM模式的

【Command.cs】

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace TreeGridDemo.MvvmHelper
{
    /// <summary>
    /// 命令
    /// </summary>
    public class Command : ICommand
    {
        /// <summary>
        /// 检查命令是否可以执行的事件,在UI事件发生导致控件状态或数据发生变化时触发
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }
            remove
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }

        /// <summary>
        /// 判断命令是否可以执行的方法
        /// </summary>
        private Func<object, bool> _canExecute;

        /// <summary>
        /// 命令需要执行的方法
        /// </summary>
        private Action<object> _execute;

        /// <summary>
        /// 创建一个命令
        /// </summary>
        /// <param name="execute">命令要执行的方法</param>
        public Command(Action<object> execute) : this(execute, null)
        {
        }

        /// <summary>
        /// 创建一个命令
        /// </summary>
        /// <param name="execute">命令要执行的方法</param>
        /// <param name="canExecute">判断命令是否能够执行的方法</param>
        public Command(Action<object> execute, Func<object, bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        /// <summary>
        /// 判断命令是否可以执行
        /// </summary>
        /// <param name="parameter">命令传入的参数</param>
        /// <returns>是否可以执行</returns>
        public bool CanExecute(object parameter)
        {
            if (_canExecute == null) return true;
            return _canExecute(parameter);
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            if (_execute != null && CanExecute(parameter))
            {
                _execute(parameter);
            }
        }
    }

    public class Command<T> : ICommand
    {
        /// <summary>
        /// 检查命令是否可以执行的事件,在UI事件发生导致控件状态或数据发生变化时触发
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }
            remove
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }

        /// <summary>
        /// 判断命令是否可以执行的方法
        /// </summary>
        private Func<T, bool> _canExecute;

        /// <summary>
        /// 命令需要执行的方法
        /// </summary>
        private Action<T> _execute;

        /// <summary>
        /// 创建一个命令
        /// </summary>
        /// <param name="execute">命令要执行的方法</param>
        public Command(Action<T> execute) : this(execute, null)
        {
        }

        /// <summary>
        /// 创建一个命令
        /// </summary>
        /// <param name="execute">命令要执行的方法</param>
        /// <param name="canExecute">判断命令是否能够执行的方法</param>
        public Command(Action<T> execute, Func<T, bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        /// <summary>
        /// 判断命令是否可以执行
        /// </summary>
        /// <param name="parameter">命令传入的参数</param>
        /// <returns>是否可以执行</returns>
        public bool CanExecute(object parameter)
        {
            if (_canExecute == null) return true;
            return _canExecute((T)parameter);
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            if (_execute != null && CanExecute(parameter))
            {
                _execute((T)parameter);
            }
        }
    }
}

【EventCommand.cs】

代码语言:javascript
复制
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace TreeGridDemo.MvvmHelper
{
    /// <summary>
    /// 事件命令   需要到nuget 安装 System.Windows.Interactivity
    /// </summary>
    public class EventCommand : TriggerAction<DependencyObject>
    {

        /// <summary>
        /// 事件要绑定的命令
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MsgName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(EventCommand), new PropertyMetadata(null));

        /// <summary>
        /// 绑定命令的参数,保持为空就是事件的参数
        /// </summary>
        public object CommandParateter
        {
            get { return (object)GetValue(CommandParateterProperty); }
            set { SetValue(CommandParateterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CommandParateter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandParateterProperty =
            DependencyProperty.Register("CommandParateter", typeof(object), typeof(EventCommand), new PropertyMetadata(null));

        //执行事件
        protected override void Invoke(object parameter)
        {
            if (CommandParateter != null)
                parameter = CommandParateter;
            var cmd = Command;
            if (cmd != null)
                cmd.Execute(parameter);
        }
    }
}

【MultiValueConverter.cs】 

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace TreeGridDemo.MvvmHelper
{
    /// <summary>
    /// 转换器
    /// </summary>
    public class MultiValueConverter: IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType,object parameter, System.Globalization.CultureInfo culture)
        {
            //必须新new一个,否则拿不到数据,因为values在返回之后,就会被清空了
            return values.Clone();
        }

        public object[] ConvertBack(object value, Type[] targetTypes,object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

【NotifyObject.cs】 

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TreeGridDemo.MvvmHelper
{
    /// <summary>
    /// 通知对象
    /// </summary>
    public class NotifyObject : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// 属性发生改变时调用该方法发出通知
        /// </summary>
        /// <param name="propertyName">属性名称</param>
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void SetAndNotifyIfChanged<T>(string propertyName, ref T oldValue, T newValue)
        {
            if (oldValue == null && newValue == null) return;
            if (oldValue != null && oldValue.Equals(newValue)) return;
            if (newValue != null && newValue.Equals(oldValue)) return;
            oldValue = newValue;
            RaisePropertyChanged(propertyName);
        }
    }
}

所有代码都已奉上,还有个图片,到时自行修改下

下面也把源码奉上

下载地址:https://shunnet.lanzoum.com/b01denptg    密码:Shunli

下载不鸟了,也请直接评论哦,看到后第一时间更新  

如果觉得可以就点赞收藏加关注吧

“关注[顺网]微信公众号,了解更多更有趣的实时信息”

本文作者:[博主]大顺

本文链接:https://shunnet.top/bErMba

版权声明:转载注明出处,谢谢

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档