我们知道,wpf冻结左侧列是很简单的,微软提供给我们了FrozenColumnCount属性,它的值代表你要从左往右冻结几列,如下图所示: 在这里插入图片描述
但是 这往往不是我们想要的,我们习惯于冻结右边的列,来实现固定操作列,删除,修改等等,遗憾的是,官方并没有提供支持,于是我们只能通过修改样式来实现.
先上效果:
在这里插入图片描述
我们实现了和网页一样丝滑的右侧固定列,并且使用起来及为方便,接下来我们看看代码是如何实现的.

.xaml

<controls:DataGrid  RightFrozenCount="2" FrozenColumnCount="1"  x:Name="listView" Margin="0 10 0 0" LoadingRow="listView_LoadingRow" Style="{StaticResource DesignDataGrid2}">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="很长很长的标题" Binding="{Binding Index1}"/>
                            <DataGridTextColumn Header="第3"  Binding="{Binding Index2}"/>
                            <DataGridTextColumn Header="第四"  Binding="{Binding Index3}"/>
                            <DataGridTextColumn Header="第五"  Binding="{Binding Index4}"/>
                            <DataGridTextColumn Header="第六"  Binding="{Binding Index2}"/>
                            <DataGridTextColumn Header="第七"  Binding="{Binding Index3}"/>
                            <DataGridTextColumn Header="第八"  Binding="{Binding Index6}"/>
                            <DataGridTextColumn Header="第九"  Binding="{Binding Index6}"/>
                            <DataGridTextColumn Header="第十"  Binding="{Binding Index1}"/>
                            <DataGridTextColumn Header="第十一"  Binding="{Binding Index6}"/>
                            <DataGridTextColumn Header="第十二"  Binding="{Binding Index1}"/>
                            <DataGridTemplateColumn Header="操作">
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal" Margin="6 0" VerticalAlignment="Center" HorizontalAlignment="Center">
                                            <Button Content="修改" Margin="0" FontSize="15" Padding="0" BorderThickness="0" Background="Transparent"/>
                                            <Button Content="删除" Padding="0" FontSize="15" Margin="20 0 0 0" BorderThickness="0" Background="Transparent"/>
                                        </StackPanel>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                        </DataGrid.Columns>
                    </controls:DataGrid>

我们通过自定义的依赖属性RightFrozenCount来冻结右侧的列

        <Style x:Key="DesignDataGridRow2" TargetType="{x:Type DataGridRow}">
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="Foreground" Value="#332E2E"/>
            <Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
            <Setter Property="ValidationErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <TextBlock
                        Margin="2,0,0,0"
                        VerticalAlignment="Center"
                        Foreground="#d50000"
                        Text="!" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridRow}">
                        <Border
                        x:Name="DGR_Border"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"                    
                        SnapsToDevicePixels="True" >
                            <SelectiveScrollingGrid>
                                <SelectiveScrollingGrid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" />
                                </SelectiveScrollingGrid.ColumnDefinitions>
                                <SelectiveScrollingGrid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="Auto" />
                                </SelectiveScrollingGrid.RowDefinitions>
                                <DataGridCellsPresenter
                                Grid.Column="1"
                                ItemsPanel="{TemplateBinding ItemsPanel}"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                <DataGridDetailsPresenter
                                Grid.Row="1"
                                Grid.Column="1"
                                SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                                Visibility="{TemplateBinding DetailsVisibility}" />
                                <DataGridRowHeader
                                Grid.Row="0"
                                Grid.RowSpan="2"
                                Grid.Column="0"
                                SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
                                Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                            </SelectiveScrollingGrid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#b8dcff" />
                    <Setter Property="assist2:DataGridAssist.MouseOverItem" Value="{Binding RelativeSource={RelativeSource  Mode=FindAncestor,AncestorType={x:Type controls:DataGrid}}}"/>
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="#b8dcff" />
                </Trigger>
                <!--<Trigger Property="IsNewItem" Value="True">
                    <Setter Property="Margin" Value="{Binding NewItemMargin, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                </Trigger>-->
            </Style.Triggers>
        </Style>
        <Style x:Key="DesignDataGrid2" TargetType="{x:Type controls:DataGrid}">
            <Setter Property="IsReadOnly" Value="True"/>
            <Setter Property="Background" Value="White" />
            <Setter Property="Foreground" Value="#DD000000" />
            <Setter Property="BorderBrush" Value="#1F000000" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="AutoGenerateColumns" Value="False" />
            <Setter Property="CanUserAddRows" Value="False" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="GridLinesVisibility" Value="Horizontal" />
            <Setter Property="HorizontalGridLinesBrush">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource RemoveAlphaBrushConverter}">
                        <Binding Path="BorderBrush" RelativeSource="{RelativeSource Self}" />
                        <Binding Path="Background" RelativeSource="{RelativeSource Self}" />
                    </MultiBinding>
                </Setter.Value>
            </Setter>
            <Setter Property="VerticalGridLinesBrush" Value="{Binding HorizontalGridLinesBrush, RelativeSource={RelativeSource Self}}" />
            <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
            <Setter Property="HeadersVisibility" Value="Column" />
            <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
            <Setter Property="ScrollViewer.PanningMode" Value="Both" />
            <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
            <Setter Property="RowStyle" Value="{StaticResource DesignDataGridRow2}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type controls:DataGrid}">
                        <Border
                        Padding="{TemplateBinding Padding}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="{TemplateBinding assist:DataGridAssist.CornerRadius}"
                        SnapsToDevicePixels="True">
                            <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                                <ScrollViewer.Template>
                                    <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="Auto" />
                                                <ColumnDefinition Width="*" />
                                                <ColumnDefinition Width="Auto" />
                                                <ColumnDefinition Width="Auto" />
                                            </Grid.ColumnDefinitions>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto" />
                                                <RowDefinition Height="*" />
                                                <RowDefinition Height="Auto" />
                                            </Grid.RowDefinitions>
                                            <Border BorderThickness="0 0 0 0" Grid.Column="2" Grid.RowSpan="2" BorderBrush="#1F000000" >
                                                <ContentControl Content="{Binding RightFrozenDataGrid,RelativeSource={RelativeSource AncestorType={x:Type controls:DataGrid}}}"/>
                                            </Border>
                                            <Border
                                            Grid.Row="0"
                                            Grid.Column="1"
                                            Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">
                                                <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" />
                                            </Border>
                                            <ScrollContentPresenter
                                            x:Name="PART_ScrollContentPresenter"
                                            Grid.Row="1"
                                            Grid.Column="0"
                                            Grid.ColumnSpan="2"
                                            CanContentScroll="{TemplateBinding CanContentScroll}" />
                                            <ScrollBar
                                            x:Name="PART_VerticalScrollBar"
                                            Grid.Row="1"
                                            Style="{StaticResource ScrollBarStyle}"
                                            Grid.Column="3"
                                            Maximum="{TemplateBinding ScrollableHeight}"
                                            Orientation="Vertical"
                                            ViewportSize="{TemplateBinding ViewportHeight}"
                                            Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                            Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
                                            <Grid Grid.Row="3" Grid.Column="1">
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                                                    <ColumnDefinition Width="*" />
                                                </Grid.ColumnDefinitions>
                                                <ScrollBar
                                                x:Name="PART_HorizontalScrollBar"
                                                Grid.Column="1"
                                                Maximum="{TemplateBinding ScrollableWidth}"
                                                Orientation="Horizontal"
                                                Style="{StaticResource ScrollBarStyle}"
                                                ViewportSize="{TemplateBinding ViewportWidth}"
                                                Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                                Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
                                            </Grid>
                                        </Grid>
                                    </ControlTemplate>
                                </ScrollViewer.Template>
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </ScrollViewer>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsGrouping" Value="true" />
                    </MultiTrigger.Conditions>
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
                </MultiTrigger>
            </Style.Triggers>
        </Style>

DataGrid.cs

    public class DataGrid: System.Windows.Controls.DataGrid
        private ScrollViewer mianScrollViewer;
        private ItemsControl itemsControl;
        private DataGrid rightDataGrid;
        public object RightFrozenDataGrid
            get { return (object)GetValue(RightFrozenDataGridProperty); }
            set { SetValue(RightFrozenDataGridProperty, value); }
        // Using a DependencyProperty as the backing store for RightFrozenDataGrid.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightFrozenDataGridProperty =
            DependencyProperty.Register("RightFrozenDataGrid", typeof(object), typeof(DataGrid), new PropertyMetadata(null));
        public object MouseOverItem
            get { return (object)GetValue(MouseOverItemProperty); }
            set { SetValue(MouseOverItemProperty, value); }
        // Using a DependencyProperty as the backing store for MouseOverItem.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseOverItemProperty =
            DependencyProperty.Register("MouseOverItem", typeof(object), typeof(DataGrid), new PropertyMetadata(null, OnMouseOverItemChanged));
        private static void OnMouseOverItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            if (d != null && d is DataGrid grid)
                // 获取当前可见行的可视元素
                if(grid.rightDataGrid != null)
                    foreach (var item in grid.Items)
                        var mainDataGridRow = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
                        if (mainDataGridRow != null) {
                            var row = grid.rightDataGrid?.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
                            if (row != null) {
                                row.Background = mainDataGridRow.Background;
        public int RightFrozenCount
            get { return (int)GetValue(RightFrozenCountProperty); }
            set { SetValue(RightFrozenCountProperty, value); }
        // Using a DependencyProperty as the backing store for RightFrozenCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightFrozenCountProperty =
            DependencyProperty.Register("RightFrozenCount", typeof(int), typeof(DataGrid), new PropertyMetadata(0, OnRightFrozenCountChanged));
        private static void OnRightFrozenCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        public DataGrid()
            Loaded += DataGrid_Loaded;
            SelectionChanged += (e, s)=> BackgroundChanged();
            MouseLeave += (e, s) => BackgroundChanged();
            MouseEnter += (e, s) => BackgroundChanged();
        private void DataGrid_Loaded(object sender, System.Windows.RoutedEventArgs e)
            if (Items != null&& Columns.Count>0&& RightFrozenCount>0) {
                rightDataGrid = new DataGrid();
                rightDataGrid.Background = Brushes.Transparent;
                rightDataGrid.BorderThickness = new Thickness(0);
                rightDataGrid.Style = Style;
                rightDataGrid.Columns.Clear();
                rightDataGrid.AutoGenerateColumns = false;
                for (int i = 0; i < RightFrozenCount; i++)
                    var last = Columns[Columns.Count - 1];
                    Columns.Remove(last);
                    rightDataGrid.Columns.Insert(0,last);
                rightDataGrid.ItemsSource = ItemsSource;
                rightDataGrid.HeadersVisibility = DataGridHeadersVisibility.Column;
                rightDataGrid.IsReadOnly = true;
                rightDataGrid.CanUserAddRows = false; 
                rightDataGrid.SelectionChanged += (e, s) => {
                    SelectedItem = rightDataGrid.SelectedItem;
                RightFrozenDataGrid = rightDataGrid;
            if (mianScrollViewer != null && rightDataGrid != null)
                mianScrollViewer.ScrollChanged += (e, s) =>
                    if (rightDataGrid.GetTemplateChild("DG_ScrollViewer") is ScrollViewer scroll)
                        scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
                        scroll.ScrollToVerticalOffset(mianScrollViewer.VerticalOffset);
        private void BackgroundChanged() {
            if (rightDataGrid != null)
                foreach (var item in Items)
                    var mainDataGridRow = ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
                    if (mainDataGridRow != null)
                        var row = rightDataGrid?.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
                        if (row != null)
                            row.Background = mainDataGridRow.Background;
        public override void OnApplyTemplate()
            base.OnApplyTemplate();
            mianScrollViewer = GetTemplateChild("DG_ScrollViewer") as ScrollViewer;
            if (mianScrollViewer != null) {

附加属性DataGridAssist.cs

 public class DataGridAssist
        public static readonly DependencyProperty MouseOverItemProperty
            = DependencyProperty.RegisterAttached("MouseOverItem", typeof(object), typeof(DataGridAssist),
                new PropertyMetadata(null, OnMouseOverItemChanged));
        private static void OnMouseOverItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            if ( e.NewValue is Cloud.Test.Wpf.Controls.DataGrid dataGrid) {
                dataGrid.MouseOverItem = d;
        public static object GetMouseOverItem(DataGridRow element)
            => (object)element.GetValue(MouseOverItemProperty);
        public static void SetMouseOverItem(DataGridRow element, object value)
            => element.SetValue(MouseOverItemProperty, value);

整合中,和其他UI界面编辑完成一起发出来

固定右侧DataGridHelper.RightFrozenColumnCount=“1” (自定义的附加属性)固定的背景色:DataGridHelper.FrozenColumnBackground。固定左侧:FrozenColumnCount =“1”1、nuget搜索XiaFControl下载。QQ技术交流群:371769310。2、在App.xaml引入资源。 1) 冻结DataGridViewColumn.Frozen 属性为 True 时, 该左侧的所有固定, 横向滚动时固定不随滚动条滚动而左右移动。这对于重要固定显示很有用。 [VB.NET]' DataGridView1的左侧2固定DataGridView1.Columns(1).Frozen=True [C#]// DataGridVie...  锁定dataGridView左边的,使锁定的不随水平滚动条滚动方法一:dataGridView1.Columns[0].Frozen = true;  //只锁定第0dataGridView1.AllowUserToOrderColumns = true; //更改栏位顺序 方法二:1.dataGridView的contextMenuStrip属性设定为 值得注意的是,DataGridView中,只能将固定在左侧,若设置了某Forzon属性为True,这左侧的所有都将被冻结,原有显示顺序不变。而GridView中,若设置了某的Fixed属性,所有的VisibleIndex都自动被调整,也就是说第一个设置Fixed值为L 今天上网找了好久,用了个笨方法,css来实现,据说VS 2005 dataview就可以,可惜小弟还苦苦使用vs 2003现在把我的方法分享下第一步:添加datagrid的itembound事件选择需要冻结的css样式 //冻结前7            e.Item.Cells[0].CssClass = "locked";            e.Item.Cel 1 <Window x:Class="WpfApplication4.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xam... 一、基础知识 1、DataGrid控件:用来显示数据的控件,从对象集合中获取信息并在具有行和单元格的网格中显示信息。每行和单独的对象相对应,并且每和对象的某个属性相对应。 2、在DataGrid 中同时包含“自动生成”与“用户自定义” 由属性AutoGenerateColumns控制。 <DataGrid Name="dataGrid1" AutoGenerateColumns... WPF DataGrid 通过自定义表头模拟首行固定独立观察员 2021 年 9 月 25 日最近工作中要在WPF中做个表格,自然首选就是DataGrid控件了。问题是,UI 设计... WPFDataGrid的使用技巧—宽调整和排序问题DataGridWPF中经常用到的控件,用来显示用户数据,功能非常强大。今天在开发的时候,业主要求修改数据显示窗口的显示风格,要求宽不能调整,且之间不允许拖拽。这个问题其实很简单,涉及到DataGrid的两个属性:①CanUserResizeColumns;②CanUserReorderColumns。但是,实际使用的过程中非常容易混 日常工作中,我们的表格中经常会有跨表引用其他表格的情况,查看表格时,就需要同时打开多个表格查看;当我们一个表格特别大时,需要对比查看前后或者左右的数据等等,这些问题在平时貌似不起眼,但是学会一些小技巧后,可以大大提升表格的查看效率。今天考呀呀会计教育就来给大家介绍在excel中一些数据呈现的小技巧。 同时冻结进行查看在查看公司的商品明细表时,我需要对比查看不同时间的商品数量信息。如下图所示的表...