tags:

views:

29

answers:

2

I am developing a WPF 4.0 application where I need to make a grid that contains a column with either textbox or a dropdown depending on the row. Example:

| Name      |  Value                   | Help                                   |
| PROP1A    | [textbox]                | Description of prop1a                  |
| Prop2A    | [dropdown v]             | Description of prop2a                  |
| Prop3A    | [textbox] [x checkbox]   | Description of prop2a                  |
| Prop4A    | [dropdown v]             | Description of prop2a                  |
| etc...

The idea is that the user has a table of values that they need to input, and we display the name and description for each value alongside. Some of the values are numbers that need to be input with a textbox, while others are a textbox plus a checkbox, and still others are a dropdown.

My initial thought was to implements this as basically a collection of what I'll call RowDescriptors that would specify the name, input type and help info (which is just text), and then use binding to bind the collection to the DataGrid. Basically, these would act as ViewModels, and setting the value in the DataGrid would flow up through the ViewModel to the actual Model (just like the in the typical case for an MVVM app).

As I looked through the documentation I have available, though, I couldn't find anywhere that discussed a way of changing the type of the column dynamically like this. I am now leaning toward using a Grid instead, and manually laying out the inputs (still using Binding, but binding each element individually). This will be a lot more manual effort on my part though, so I wanted to find out if there was a relatively-straightforward way of implementing my first idea. It seems like I should be able to do something with DataGridTemplateColumn, but I'm relatively new to WPF and I'm not sure exactly how I'd go about doing this.

A: 

I had to do this once in an ASP.NET application with a GridView, and though it's a different technology I think the answer will be the same. What I had to do was simply add ALL of the different kinds of controls in each cell, but initially leave them not visible.

Then you can override whatever event is fired after each item is bound to the row in the grid (I'm new to WPF as well, I'm not sure what the events are), change the visibility of the appropriate control in the cell based on whatever information you know in the object you're binding for that row, and then populate or bind the control to the appropriate value.

It does get to be more fun when you need to get the values back out, but I think I ended up search for the control that was visible and then making a decision based on the control's type. I think this is about the only way you're going to be able to accomplish it, since every grid control I've used from Microsoft seems to assume that your columns will never need different types of controls.

I've asked nearly the same question before on SO. Here's the post. Maybe it will get the ball rolling for you.

Cory Larson
+1  A: 

You can do that using a template column.

This one will show one or two text boxes depending on the data in the row.

The CellTemplate is shown normally, but it is replaced with CellEditingTemplate when the row is edited.

<DataGridTemplateColumn Header="Value" Width="350">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock 
            Text="{Binding EffectiveValue,Mode=OneWay,ValidatesOnDataErrors=True}" 
            ToolTip="{Binding EffectiveValue,Mode=OneWay}"
            TextWrapping="Wrap"
            />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>

    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>


                <TextBlock  Text="Value" Margin="4"/>
                <TextBox 
                Grid.Column="1"
                Text="{Binding ConfigurationValue,ValidatesOnDataErrors=True}" 
                ToolTip="{Binding ConfigurationValue}"
                TextWrapping="Wrap"
                AcceptsReturn="{Binding DataType, Mode=OneWay, 
                                    Converter={StaticResource ResourceKey=StringMatchBooleanConverter}, ConverterParameter=String}"
                gui:FocusAttacher.Focus="True" 
                />

                <TextBlock  Text="Default Value" Grid.Row="1" Margin="4"
                Visibility="{Binding DefaultConfigurationValue, Converter={StaticResource ResourceKey=NullVisibilityConverter}}"
                        />
                <TextBox 
                Grid.Column="1" 
                Grid.Row="1"
                Text="{Binding DefaultConfigurationValue, Mode=OneWay }" 
                ToolTip="{Binding DefaultConfigurationValue, Mode=OneWay}"
                TextWrapping="Wrap"
                IsReadOnly="True" 
                Visibility="{Binding DefaultConfigurationValue, Converter={StaticResource ResourceKey=NullVisibilityConverter}}"

                />

            </Grid>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Jonathan Allen
This is basically a WPF version of Cory Larson's approach, where you have all of the types in the row, and then show or hide the appropriate ones, right? (Difference being that in your example, this is accomplished via binding, right?)
notJim
I haven't had a chance to look at his code. This was just fresh in my mind because I learned how to do it less than a week ago.
Jonathan Allen