先来简单的了解下什么是MVVM模式
简单官解如下:
MVVM其实就是:Model 、View、ViewModel三个的简称,就像MVC一样。 Model就是模型。View就是视图。ViewModel就是和view进行绑定的。
我的理解就是:
就是前后端分离,通过数据绑定或双向绑定的形式来更新界面
切入正题,怎么用MVVM实现[自定义表格带展开缩放效果,并且可以获取点击行的数据,还可以单独更新某列或行数据]
先来看一下界面
只做了一级节点,对于我工作项目来说,一级节点够用了,需要整多级节点的,可以联系我,也可以自己研究
接下来就直接上代码,源码请滑至最下面,自行下载
【前端标红的代码得特别注意哦】
主界面前端代码
【Demo.xaml】
<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】
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】
<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】
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】
<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】
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】
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】
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】
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】
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】
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
版权声明:转载注明出处,谢谢 ☺
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有