4

Is it possible to have a WPF Toolkit Data Grid's DataGridComboBoxColumn "exposed" when the Data Grid loads? By default you have to click in the cell to expose the combo box. I'd like the user to see that the combo box is available without having to click in the cell. I would prefer that the combo box be immediately available and the first click in the cell makes the combo box actually drop down. Currently you have to click the cell and then click the combo box drop down to expose the values.

Unwanted appearance

V.S.

Correct appearance

XAML:

<dg:DataGridComboBoxColumn x:Name="ctrlStatus" Header="Status" Width="Auto" SelectedValueBinding="{Binding Port}" SelectedValuePath="Status">
  <dg:DataGridComboBoxColumn.CellStyle>
    <Style TargetType="dg:DataGridCell">
      <EventSetter Event="Selector.SelectionChanged" Handler="SelectionChanged"/>
    </Style>
  </dg:DataGridComboBoxColumn.CellStyle>
</dg:DataGridComboBoxColumn>

Code Behind:

List<string> _statusList;
public List<string> StatusList
{
  get 
  {
      return _statusList; 
  }
  set
  {
    _statusList = value;
    ctrlStatus.ItemsSource = _statusList;
  }
}

Thanks, GAR8

Final SOLUTION: XAML

<telerik:GridViewComboBoxColumn Header="Status">
  <telerik:GridViewComboBoxColumn.CellTemplate>
    <DataTemplate>
      <telerik:RadComboBox ItemsSource="{Binding StatusList,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" SelectedValue="{Binding Port}" SelectedValuePath="Status" SelectionChanged="SelectionChanged"/>
    </DataTemplate>
  </telerik:GridViewComboBoxColumn.CellTemplate>
</telerik:GridViewComboBoxColumn>

Code Behind:

List<string> _statusList;
public List<string> StatusList 
{
  get { return _statusList;  }
  set { _statusList = value; }
}
GAR8
  • 293
  • 1
  • 5
  • 14

3 Answers3

2

You can use a DataGridTemplateColumn and place a ComboBox as the cell edit template without specifying a non-edit template. This will let the DataGrid use always the ComboBox.

Update
As requested in your comment, below an example. Please note that the example is not optimal and I would have choosen another design, but I have done it in a way so that it should integrate in your solution without bigger problems. I have not tested it. Make a comment if they are errors in.

<DataGridTemplateColumn>    
     <DataGridTemplateColumn.CellEditingTemplate >       
           <DataTemplate>         
                 <ComboBox x:Name="ctrlStatus" 
                        SelectedValueBinding="{Binding Port}" 
                        SelectedValuePath="Status">  
                        SelectionChanged="SelectionChanged"
                        ItemsSource="{Binding StatusList,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" 
                  />       
           </DataTemplate>    
     </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

To use the above code, StatusList must implement change notification. If your DataGrid is not in aWindow but in another class such as in a UserControl, replace the type name in the relative source.

HCL
  • 36,053
  • 27
  • 163
  • 213
  • I tried that but then I lost the x:Name ref to my control that I used for binding. Do you have an example that will allow binding and selection changed. I added my code to the question. – GAR8 Aug 09 '11 at 17:22
  • @GAR8: I have extended my answer. – HCL Aug 09 '11 at 17:57
  • The problem with this approach is it loses binding because x:Name="ctrlStatus" is not visible in the code behind. – GAR8 Aug 09 '11 at 18:23
  • @GAR8: Good point, this makes sense. I never used it this way. Declare the ItemsSource also over a binding (probably over RelativeSource to your ContainerControl, I assume it's a UserControl or a Window). Don't forget to implement INotifyPropertyChanged for your StatusList-property. The binding would look something like that: ItemsSource="{Binding StatusList,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" . If it's in a user control, replace "Window" through "UserControl". – HCL Aug 09 '11 at 18:29
  • HCL Thanks, I found that using CellTemplate alone and your RelativeSource binding approach solved the problem. Just using CellEditingTemplate will not work, it doesn't present as a combo box at runtime. I've update the original question with my completed xaml of the status combo box. – GAR8 Aug 09 '11 at 22:00
  • HCL - additional testing reveals that the data is bound but two things are still wrong. 1) The data displayed is always index 0 and not the actual value found in the database. 2) Changes made in the containing grid are not able to be extracted to save back to the database. Any thoughts? – GAR8 Aug 19 '11 at 01:57
  • @GAR8: I have seen that you posted code in your updated for the Telerik DataGrid. I was not aware that you use this control, I have thought your question was about the Microsoft DataGrid. I don't know the Telerik controls, never worked with them. But from your description of the problems, I assume that the value binding does not work. Do you bind to a DependencyProperty or a CLR property? For the DP: specify TwoWay-Binding if defined in the meta data. For the CLR property, check if INotifyPropertyChanged is implementet and PropertyChanged is called. Maybe it's better to open a new question... – HCL Aug 19 '11 at 07:48
  • HCL I apologize for the control switch. It was a last minute demand and it still worked with Telerik. Personally I prefer the MS Data Grid. Unfortunately I have a looming deadline and don't have time to troubleshoot this further. I've rolled back to the standard combo box three click to change BS. I'll investigate thus further when time permits. G – GAR8 Aug 19 '11 at 15:45
2

Try this

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
       <DataTemplate>
           <ComboBox ItemsSource=”{Binding Path=YourSource...}” 
         Text=”{Binding Path=YourSource...}”/>
       </DataTemplate>
       </DataGridTemplateColumn.CellTemplate>
       <DataGridTemplateColumn.CellEditingTemplate >
       <DataTemplate>
         <ComboBox ItemsSource=”{Binding Path=YourSource...}” 
         Text=”{Binding Path=YourSource...}”/>
       </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

Basically you define the ComboBox in both cases which are CellTemplate and CellEditingTemplate.

See this post which I wrote some time ago, in that I wrote separate template for non editing( which you see initially) and editing (which you see when you click i.e combobox) state of cell. Now you can copy the code of editing in non-editing as I have done in XAML above and your problem will be solved

Haris Hasan
  • 29,856
  • 10
  • 92
  • 122
  • I like this approach, however, binding is still an issue for me. I'm not using MVVM. Can you help with binding with this approach? See my updated original post that shows my XAML and Code Behind. I'm binding to the Status combo box via x:Name"ctrlStatus". – GAR8 Aug 09 '11 at 18:14
  • In the code behind you have a `public property StatusList` right? and you are already binding the `SelectedValueBinding` and `SelectedValuePath` which means you are setting some `DataContext`. Now simply do ` – Haris Hasan Aug 09 '11 at 18:25
0

If you need to use this often, then a custom column can be defined:

public class DataGridCustomComboBoxColumn : DataGridComboBoxColumn
{
    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        return base.GenerateEditingElement(cell, dataItem);
    }
}

This can then be used in place of the normal DataGridComboBoxColumn.

g t
  • 7,287
  • 7
  • 50
  • 85