在动态DataGrid中启用Text Wrap

时间:2012-02-10 06:49:08

标签: c# .net wpf c#-4.0 wpfdatagrid

我正在动态生成DataGrid并将其添加到我的WPF应用程序上的StackPanel

由于它是动态生成的,因此XAML方面没有标记,我需要以编程方式管理绑定和所有属性。

如果文本很长,我希望我的DataGrid将单元格中的值包装到下一行。我了解我需要将DataGridCell替换为TextBlock并在其上设置TextWrap属性。我发现的所有例子都提出了这些问题。但是,如果没有XAML,我无法找到完全从代码背后完成的方法。

到目前为止,我已尝试使用以下代码,但它无效。

DataGrid dg = new DataGrid();   

dg.ItemsSource = ((DataSet)data).Tables[0].DefaultView;
dg.DataContext = ((DataSet)data).Tables[0].DefaultView; 

DataTemplate ct = new DataTemplate(typeof(DataGridCell));
FrameworkElementFactory tb = new FrameworkElementFactory(typeof(TextBlock));
tb.SetValue(TextBlock.TextWrappingProperty, TextWrapping.Wrap);
ct.VisualTree = tb;

dg.ItemTemplate = ct;
dg.ColumnWidth = 300;

请你指点我正确的方向吗?

[更新]:解决方案

在进一步研究中,我能够解决我的问题。对于自动生成的列,我们需要捕获AutoGeneratingColumn事件,并将DataGridTextColumn替换为DataGridTemplateColumn,其中包含TextBlock。然后我们可以设置`TextWrappingProperty'来包装文本。

以下是更新的代码:

DataGrid dg = new DataGrid();   

dg.ItemsSource = ((DataSet)data).Tables[0].DefaultView;
dg.DataContext = ((DataSet)data).Tables[0].DefaultView; 

DataTemplate ct = new DataTemplate(typeof(DataGridCell));
FrameworkElementFactory tb = new FrameworkElementFactory(typeof(TextBlock));
tb.SetValue(TextBlock.TextWrappingProperty, TextWrapping.Wrap);
ct.VisualTree = tb;

dg.AutoGeneratingColumn += new EventHandler<DataGridAutoGeneratingColumnEventArgs>(dg_AutoGeneratingColumn);

dg.MaxColumnWidth = 300;

然后是事件处理程序下的代码:

 private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
        //cancel the auto generated column
        e.Cancel = true;

        //Get the existing column
        DataGridTextColumn dgTextC = (DataGridTextColumn)e.Column;

        //Create a new template column 
        DataGridTemplateColumn dgtc = new DataGridTemplateColumn();

        DataTemplate dataTemplate = new DataTemplate(typeof(DataGridCell));

        FrameworkElementFactory tb = new FrameworkElementFactory(typeof(TextBlock));
        tb.SetValue(TextBlock.TextWrappingProperty, TextWrapping.Wrap);
        dataTemplate.VisualTree = tb;

        dgtc.Header = dgTextC.Header;
        dgtc.CellTemplate = dataTemplate;

        tb.SetBinding(TextBlock.TextProperty, dgTextC.Binding);

        //add column back to data grid
        DataGrid dg = sender as DataGrid;
        dg.Columns.Add(dgtc);
    }

2 个答案:

答案 0 :(得分:4)

另一种方法是使用这样的行为。

  public class DataGridWrapTextBehaviour : Behavior<DataGrid>
  {
     private DataGrid DataGrid
     {
        get { return AssociatedObject as DataGrid; }
     }

     private Style ElementStyle { get; set; }
     private Style EditingElementStyle { get; set; }

     protected override void OnAttached()
     {
        base.OnAttached();

        this.ElementStyle = new Style( typeof( TextBlock ) );
        this.ElementStyle.Setters.Add( new Setter( TextBlock.TextWrappingProperty, TextWrapping.Wrap ) );

        this.EditingElementStyle = new Style( typeof( TextBox ) );
        this.EditingElementStyle.Setters.Add( new Setter( TextBox.TextWrappingProperty, TextWrapping.Wrap ) );

        this.DataGrid.Columns.CollectionChanged += Columns_CollectionChanged;
     }

     protected override void OnDetaching()
     {
        this.DataGrid.Columns.CollectionChanged -= Columns_CollectionChanged;
        base.OnDetaching();
     }

     private void Columns_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e )
     {
        foreach ( var column in this.DataGrid.Columns.OfType<DataGridTextColumn>() )
        {
           column.ElementStyle = this.ElementStyle;
           column.EditingElementStyle = this.EditingElementStyle;
        }
     }
  }

然后,您可以将行为拖放到Expression Blend中的DataGrid上。

答案 1 :(得分:0)

我必须说的第一件事是你以错误的方式使用数据网格。

 dg.ItemTemplate = ct; 

是错误的代码!

WPF DataGrid不像其他ItemTemplate那样接受ItemsControls属性。您必须在DataGrid中提供列模板才能正常工作。

DataGridBoundColumn DataGridTextColumn列提供给DataGrid时,您可以像这样设置ElementStyle属性...

        <toolkit:DataGrid
                 AutoGenerateColumns="False">                
            <toolkit:DataGrid.Columns>
                <toolkit:DataGridTextColumn 
                         Binding="{Binding SomeProperty}">
                    <toolkit:DataGridTextColumn.ElementStyle>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="TextWrapping"
                                    Value="Wrap"/>
                        </Style>
                    </toolkit:DataGridTextColumn.ElementStyle>
                </toolkit:DataGridTextColumn>
            </toolkit:DataGrid.Columns>
        </toolkit:DataGrid>     

...其中toolkit是.Net 3.5或更早版本中WPF工具包的命名空间。在.Net 4.0中,它是标准System.Windows.Controls命名空间的一部分。

但是,在您的情况下,完全相同的解决方案有点复杂,因为默认情况下,您的网格AutoGenerateColumns为true,会自动生成DataGrid.Columns。因此,您无权设置此ElementStyle属性。

所以我们必须采用XML和代码隐藏的方法......

<强> XAML:

       <toolkit:DataGrid x:Name="dg">
            <toolkit:DataGrid.Resources>
                <Style TargetType="{x:Type TextBlock}"
                       x:Key="WrappedTextBlockStyle">
                    <Setter Property="TextWrapping" Value="Wrap"/>
                </Style>
            </toolkit:DataGrid.Resources>                
        </toolkit:DataGrid>

代码背后:

    dg.ItemsSource = ((DataSet)data).Table[0].DefaultView;
    dg.Columns.CollectionChanged
       += new NotifyCollectionChangedEventHandler(
              Columns_CollectionChanged);

    void Columns_CollectionChanged(
         object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems.Count > 0)
        {
            foreach(DataGridColumn col in e.NewItems)
            {
                if (col is DataGridTextColumn)
                {
                    ((DataGridTextColumn) col).ElementStyle
                         = dg.Resources["WrappedTextBlockStyle"] as Style;
                }
            }
        }
    }

希望这会有所帮助......

注意:请注意,包装文本块会使WPF dataGrid的性能变慢。