DataGrid

每行背景色交替

<Style x:Key="DataGridRowStyleEx" TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowBaseStyle}">
	<Setter Property="MinHeight" Value="34" />
	<Setter Property="FontSize" Value="14"/>
	<Setter Property="Background" Value="Red" />
</Style>
 <Style x:Key="DataGridCellStyleEx" TargetType="DataGridCell" BasedOn="{StaticResource DataGridCellBaseStyle}">
	<Setter Property="Padding" Value="0" />
	<Setter Property="Margin" Value="0" />
	<Setter Property="FontSize" Value="14"/>
</Style>
<Style x:Key="DataGridColumnHeaderStyleEx" TargetType="DataGridColumnHeader" BasedOn="{StaticResource DataGridColumnHeaderBaseStyle}">
	<Setter Property="BorderThickness" Value="0,0,0,2" />
	<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
	<Setter Property="Height" Value="50"/>
	<Setter Property="Padding" Value="0" />
	<Setter Property="Background" Value="{StaticResource MainBackBrush}" />
</Style>
<Style x:Key="DataGridStyleEx" TargetType="DataGrid" BasedOn="{StaticResource DataGridBaseStyle}">
	<Setter Property="RowStyle" Value="{StaticResource DataGridRowStyleEx}" />
	<Setter Property="CellStyle" Value="{StaticResource DataGridCellStyleEx}" />
	<Setter Property="ColumnHeaderStyle" Value="{StaticResource DataGridColumnHeaderStyleEx}" />
	<Setter Property="ColumnWidth" Value="*" />
	<Setter Property="RowHeight" Value="50" />
</Style>

 <DataGrid Style="{StaticResource DataGridStyleEx}"
	AlternationCount="2"
	AlternatingRowBackground="Green"
	LoadingRow="DataGrid_LoadingRow" CanUserSortColumns="False">
 </DataGrid>

表头设置

行头自动增长,列头设置文本

mxl

<UserControl.Resources>
    <cvt:ConvertItemToIndex x:Key="indexConverter"/>
    <Style x:Key="SerialNumStyle" TargetType="TextBlock">
        <Setter Property="Background" Value="WhiteSmoke" />
        <Setter Property="Foreground" Value="Gray" />
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="FontSize" Value="{Binding FontSize,RelativeSource={RelativeSource AncestorType=DataGrid}}" />
    </Style>
</UserControl.Resources>
<DataGrid x:Name="dgData" RowHeaderWidth="100" Loaded="DgData_Loaded" >
    <DataGrid.Columns>
    </DataGrid.Columns>
    <DataGrid.RowHeaderTemplate>
        <DataTemplate>
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding Converter="{StaticResource indexConverter}" ConverterParameter="">
                        <Binding RelativeSource="{RelativeSource AncestorType=DataGridRow}" />
                        <Binding Path="PageIndex" ElementName="pager" />
                        <Binding Path="PageSize" ElementName="pager" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DataTemplate>
    </DataGrid.RowHeaderTemplate>
</DataGrid>
<ctl:UC_Pager x:Name="pager"  Grid.Row="2" GetDataDelegateHandler="GetData"/>

后台

private void DgData_Loaded(object sender, RoutedEventArgs e)
{
    var dataGrid = (DataGrid)sender;
    var border = (Border)VisualTreeHelper.GetChild(dataGrid, 0);
    var scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
    var grid = (Grid)VisualTreeHelper.GetChild(scrollViewer, 0);
    var button = (Button)VisualTreeHelper.GetChild(grid, 0);
    button.IsEnabled = false;

    var textBlock = new TextBlock()
    {
        Text = "序号",
        Style = (Style)this.FindResource("SerialNumStyle"),
    };
    grid.Children.Add(textBlock);
}
using System;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;

class ConvertItemToIndex : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var row = values[0] as DataGridRow;
        var pageIndex = System.Convert.ToInt32(values[1]);
        var pageSize = System.Convert.ToInt32(values[2]);
        return (row.GetIndex() + 1 + (pageIndex - 1) * pageSize).ToString();
    }

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

行头隐藏,设置Header

<DataGrid x:Name="dgData" RowHeaderWidth="100" LoadingRow="DgData_LoadingRow">
    <DataGrid.Columns>
        <DataGridTemplateColumn  Width="55" Header="序号"  >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}}, Path=Header}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"></TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
<ctl:UC_Pager x:Name="pager" GetDataDelegateHandler="GetData"/>
private void DgData_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = e.Row.GetIndex() + 1 + (pager.PageIndex - 1) * pager.PageSize;
}

行头可勾选

<DataGrid.Columns>
    <DataGridTemplateColumn Width="50">
        <DataGridTemplateColumn.HeaderTemplate>
            <DataTemplate>
                <CheckBox x:Name="cbAll" Click="CbAll_Click" Margin="3,0,0,0"/>
            </DataTemplate>
        </DataGridTemplateColumn.HeaderTemplate>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <CheckBox Name="Select" HorizontalAlignment="Center" IsChecked="{Binding IsChecked}"/>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
    <DataGridTextColumn Header="Guid" Binding="{Binding Guid}"/>
</DataGrid.Columns>

复制单行

DataGridTextColumn可正常Ctrl+C复制,不用响应CopyingRowClipboardContent。
DataGridTemplateColumn获取null,可对模板中的控件判断类型,转换获取,并注意虚拟化的影响。代码如下:

using System.Windows.Media;
private void DgData_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
    try
    {
        var dg = sender as DataGrid;
        var result = new List<DataGridClipboardCellContent>();
	// 第一行鼠标所在单元格值
        var dataItem = dg.SelectedItem;
        foreach (var item in e.ClipboardRowContent)
        {
            if (item.Content == null)
            {
                var element = dg.Columns[item.Column.DisplayIndex].GetCellContent(dataItem);
                if (element == null)
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, $"<{item.Column.Header}>"));
                    // 因为虚拟化,超过可见范围的数据取不到值,可直接在数据源上查找
                    string value = string.Empty;
                    var entity = (Demo)dataItem;
                    switch (item.Column.DisplayIndex)
                    {
                        case 11:
                            value = entity.Property1;
                            break;
                        case 12:
                            value = entity.Property2;
                            break;

                        default:
                            break;
                    }
                    result.Add(new DataGridClipboardCellContent(item, item.Column, value));
                    continue;
                }
                if (element is TextBlock txt)   // DataGridTextColumn
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, txt.Text));
                }
                else if (VisualTreeHelper.GetChild(element, 0) is TextBlock txt2)   // DataGridTemplateColumn
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, txt2.Text));
                }
            }
            else
            {
                result.Add(new DataGridClipboardCellContent(item, item.Column, item.Content.ToString()));
            }
        }
        e.ClipboardRowContent.Clear();
        e.ClipboardRowContent.AddRange(result);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

复制多行

private int _clipboardCalledCnt = 0;
private void DgData_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
{
    try
    {
        var dg = sender as DataGrid;
        int rowCnt = dg.SelectedItems.Count;
        var result = new List<DataGridClipboardCellContent>();
        var dataItem = dg.SelectedItems[_clipboardCalledCnt];
        foreach (var item in e.ClipboardRowContent)
        {
            if (item.Content == null)
            {
                var element = dg.Columns[item.Column.DisplayIndex].GetCellContent(dataItem);
                if (element == null)
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, $"<{item.Column.Header}>"));
                    // 因为虚拟化,超过可见范围的数据取不到值,可直接在数据源上查找
                    string value = string.Empty;
                    var entity = (Demo)dataItem;
                    switch (item.Column.DisplayIndex)
                    {
                        case 11:
                            value = entity.Property1;
                            break;
                        case 12:
                            value = entity.Property2;
                            break;
                        default:
                            break;
                    }
                    result.Add(new DataGridClipboardCellContent(item, item.Column, value));
                    continue;
                }
                if (element is TextBlock txt)   // DataGridTextColumn
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, txt.Text));
                }
                else if (VisualTreeHelper.GetChild(element, 0) is TextBlock txt2)   // DataGridTemplateColumn
                {
                    result.Add(new DataGridClipboardCellContent(item, item.Column, txt2.Text));
                }
            }
            else
            {
                result.Add(new DataGridClipboardCellContent(item, item.Column, item.Content.ToString()));
            }
        }
        e.ClipboardRowContent.Clear();
        e.ClipboardRowContent.AddRange(result);
        _clipboardCalledCnt++;
        if (_clipboardCalledCnt == rowCnt)
        {
            _clipboardCalledCnt = 0;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

属性绑定

DataGrid中,Foreground不是DataGridTextColumn的依赖项属性,无法实现属性绑定。
可以使用DataGridTemplateColumn+TextBlock代替实现。

控件行列扩展

demo

单列提示框

<DataGridTemplateColumn Header="提示" Width="2*">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=PropertyName}" ToolTip="{Binding Path=PropertyName}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

DataGridComboBoxColumn单击响应

 <UserControl.Resources>
     <cvt:PropertyTypeConv x:Key="propertyTypeConverter" />
 </UserControl.Resources>
<ctl:SingleDataGridComboBoxColumn SelectedValueBinding="{Binding PropertyName1}" >
  <ctl:SingleDataGridComboBoxColumn.ElementStyle>
      <Style TargetType="ComboBox">
          <Setter Property="SelectedValue" Value="{Binding Path=Key, Converter={StaticResource propertyTypeConverter}}"/>
      </Style>
  </ctl:SingleDataGridComboBoxColumn.ElementStyle>
  <ctl:SingleDataGridComboBoxColumn.EditingElementStyle>
      <Style TargetType="ComboBox">
          <Setter Property="SelectedValue" Value="{Binding Path=Value}"/>
          <EventSetter Event="SelectionChanged" Handler="ComboBox_SelectionChanged"/>
      </Style>
  </ctl:SingleDataGridComboBoxColumn.EditingElementStyle>
</ctl:SingleDataGridComboBoxColumn>
class SingleDataGridComboBoxColumn : DataGridComboBoxColumn
{
  protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
  {
      object x = base.PrepareCellForEdit(editingElement, editingEventArgs);
      if ((editingEventArgs is MouseButtonEventArgs) && ((MouseButtonEventArgs)editingEventArgs).ChangedButton == MouseButton.Left)
      {
          ComboBox o = editingElement as ComboBox;
          if (o != null)
          {
              o.IsDropDownOpen = true;
          }
      }
      return x;
  }
}

虚化

UI虚拟化的原理是:但是由于显示器和人眼的限制,用户往往只会同时看到其中的数十条数据,因此只要在界面上渲染用户所看到的那些数据即可,对于用户呈现的界面仍然是一样的。

DataGrid

DataGrid默认开启虚化。渲染性能优化配置如下:

<DataGrid ItemsSource="{Binding DemoList, IsAsync=True}"
          ScrollViewer.CanContentScroll="True"   <!--False情况下,整个控件的虚拟化会取消-->
          VirtualizingPanel.IsVirtualizing="True"
          VirtualizingPanel.VirtualizationMode="Recycling"
          VirtualizingPanel.IsContainerVirtualizable="True"
          EnableColumnVirtualization="True"
          EnableRowVirtualization="True">
    <DataGrid.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel />
        </ItemsPanelTemplate>
    </DataGrid.ItemsPanel>
    <DataGrid.Columns>
        
    </DataGrid.Columns>
</DataGrid>

ItemsControl

<ItemsControl ItemsSource="{Binding DemoList}" ItemTemplate="{StaticResource key1}"
              VirtualizingPanel.IsVirtualizing="True" >
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <common:VirtualizingWrapPanel ScrollOffset="50" ChildHeight="90" ChildWidth="150"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer CanContentScroll="True"> <!--逻辑滚动-->
                <ItemsPresenter/>
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

关于UI虚化的实现,其核心则是VirtualPanel,在WPF中内置的VirtualPanel只有VirtualizingStackPanel一个,一般常用于表格之类的数据呈现。如果需要其它布局方式的Panel,比如VirtualizingWrapPanel则需要自己实现。

WPF的UI虚拟化

posted @ 2020-09-15 15:18  wesson2019  阅读(484)  评论(0编辑  收藏  举报