Включить TextWrap в динамической DataGrid - PullRequest
2 голосов
/ 10 февраля 2012

Я динамически генерирую DataGrid и добавляю его к StackPanel в своем приложении WPF.

Так как объект генерируется динамически, на стороне 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 ]

4 голосов
/ 14 декабря 2012

Альтернативный подход - использовать подобное поведение.

  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;
        }
     }
  }

Затем можно перетащить поведение в DataGrid в Expression Blend.

0 голосов
/ 10 февраля 2012

Первое, что я должен сказать, это то, что вы используете сетку данных неверным образом.

 dg.ItemTemplate = ct; 

- это неправильный код!

WPF DataGrid не поддерживает ItemTemplateсобственность как и другие ItemsControls.Вам нужно будет предоставить шаблоны столбцов в DataGrid для правильной работы.

Когда в DataGrid передаются DataGridBoundColumn \ DataGridTextColumn столбцы, вы можете установить их свойство 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>     

... where toolkit - это пространство имен инструментария WPF в версии .Net 3.5 или более ранней.В .Net 4.0 он является частью стандартного пространства имен System.Windows.Controls.

Но это точно такое же решение немного сложнее в вашем случае, потому что ваша сетка имеет AutoGenerateColumns как истинное значение по умолчанию, которое генерирует 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.

...