jfmajor
jfmajor

Reputation: 83

TextWrapping textbox in WPF DataGrid

I've been trying to make my textboxes in my DataGrid wrap. I got it working but it seems to break the Text binding.

XAML

<DataGrid x:Name="dataGrid" Grid.Row="0" AutoGenerateColumns="False" ItemsSource="{Binding}">
    <!-- <DataGrid.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type DataGridCell}">
                        <TextBox TextWrapping="Wrap" Text="{Binding Path=Value}">
                        </TextBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.CellStyle> -->
</DataGrid>

I add the columns and rows using a data set like so.

CS

    #region Variables
    private DataTable m_stringData = new DataTable();
    private DataSet m_stringDataSet = new DataSet();
    #endregion

    #region Constructors
    public LocEditor()
    {
        InitializeComponent();

        AddColumn("ID", 100);
        AddString("Test");
        dataGrid.DataContext = m_stringData;
    }
    #endregion

    #region Methods

    private void AddColumn(string l_columnName, int l_iWidth)
    {
        m_stringData.Columns.Add(l_columnName, typeof(string));

        dataGrid.Columns.Add(new DataGridTextColumn
        {
            Header = l_columnName,
            Width = l_iWidth,
            Binding = new Binding(l_columnName)
            //Binding = new Binding(string.Format("[{0}]", l_columnName))
        });
    }

    private void AddString(string l_stringID)
    {
        m_stringData.Rows.Add();
        m_stringData.Rows[m_stringData.Rows.Count - 1][0] = l_stringID;
    }

    #endregion

Any help would be greatly appreciated.

Upvotes: 3

Views: 4397

Answers (3)

jfmajor
jfmajor

Reputation: 83

Figured it out. By setting the Element and EditingElementStyle, I don't have to reset the Binding.

DataGridTextColumn l_column = new DataGridTextColumn();
l_column.Header = l_columnName;
l_column.Binding = new Binding(l_columnName);
l_column.Width = l_iWidth;

Style l_textStyle = new Style(typeof(TextBlock));
l_textStyle.Setters.Add(new Setter(TextBlock.TextWrappingProperty, TextWrapping.Wrap));
l_column.ElementStyle = l_textStyle;
Style l_textEditStyle = new Style(typeof(TextBox));
l_textEditStyle.Setters.Add(new Setter(TextBox.TextWrappingProperty, TextWrapping.Wrap));
l_column.EditingElementStyle = l_textEditStyle;

dataGrid.Columns.Add(l_column);

Upvotes: 2

Rachel
Rachel

Reputation: 132548

If you're looking to just add TextWrapping to all TextBoxes in your DataGrid, I would suggest making an implicit style for them in your DataGrid.Resources

<DataGrid.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="TextWrapping" Value="Wrap" />
    </Style>
</DataGrid.Resources>

The reason why the data isn't showing up in your Template is because you're missing the ContentPresenter. This is the object that displays the rendered content of the actual DataGridCell. The DataGridCell itself has no idea what the content of its cell is, so doesn't know what the binding is.

For example, this works

<Style TargetType="DataGridCell">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <TextBlock TextWrapping="Wrap">
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </TextBlock>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

But not this

<Style TargetType="DataGridCell">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <TextBox TextWrapping="Wrap" Text="{TemplateBinding Content}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

because the Content is whatever object happens to be in the cell at the time, whether it is a TextBox, TextBlock, ComboBox, etc

Upvotes: 0

Stuart
Stuart

Reputation: 811

This inserts the GridViewColumn directly into the GridView, but it worked for me.

<ListView Name="myListView">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="HEADER NAME" x:Name="header">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <TextBox TextWrapping="Wrap" Text="{Binding Path=Value}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

In order to see the wrapped text fully, you will need to set the height of the rows to be large enough to see this (or do height conversions dynamically).

<My:ToHeightConverter x:Key="heightConverter" />

<Style TargetType="ListViewItem">
    <Setter Property="Height" Value="{Binding ElementName=myListView, Path=ActualHeight, Converter={StaticResource heightConverter}}" />
</Style>

And then in the code behind the GridView:

[ValueConversion(typeof(double), typeof(double))]
public class ToHeightConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        return (((double)value * 10);      //return the height wanted here
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }
}

Upvotes: 1

Related Questions