msmechanized
msmechanized

Reputation: 436

DataGridTemplateColumn.CellEditingTemplate converting a TextBox to Combobox inconsistent

I have the following XAML code:

<DataGrid ItemsSource="{Binding TempParameters}" AutoGenerateColumns="False" CanUserAddRows="False" Height="100" Name="TempParameterGrid" CanUserSortColumns="False" Width="{Binding Source={StaticResource theWidth}}" MouseDown="SetSelectedGrid">
     <DataGrid.Columns>
         <DataGridTextColumn Width="*" Header="ID"  IsReadOnly="True" Binding="{Binding ID}"/>
         <DataGridTemplateColumn Header="Parameter" IsReadOnly="False" >
             <DataGridTemplateColumn.CellEditingTemplate>
                 <DataTemplate>
                     <ComboBox SelectedValue="{Binding name, Mode=TwoWay}" ItemsSource ="{Binding ParameterNames, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
                 </DataTemplate>
             </DataGridTemplateColumn.CellEditingTemplate>
             <DataGridTemplateColumn.CellTemplate>
                 <DataTemplate>
                     <TextBox Text ="{Binding name, Mode=TwoWay}" />
                 </DataTemplate>
             </DataGridTemplateColumn.CellTemplate> 
         </DataGridTemplateColumn>
         <DataGridTextColumn Width="*" Header="Start"      IsReadOnly="False" Binding="{Binding start}"/>
         <DataGridTextColumn Width="*" Header="End"        IsReadOnly="False" Binding="{Binding end}"/>
         <DataGridTextColumn Width="*" Header="Samples"    IsReadOnly="False" Binding="{Binding samples}"/>
     </DataGrid.Columns>
 </DataGrid>

The DataGrid binds to a collection property TempParameters. This is a collection of the following objects.

    public class TuneParameterRecord {
        public int ID { get; set; }
        public string name { get; set; }
        public double start { get; set; }
        public double end { get; set; }
        public int samples { get; set; }
    }

All the columns are editable. However I need the name column to have a list of predefined names. Therefore I was thinking to provide a ComboBox with a list of acceptable values (while many will point it out, this list cannot be an enum. I need this to be a list of strings). This list is provided in the window data context.

I can reference it directly providing a relative source in the CellEditingTemplate. My problem is that when i try to edit a cell in the column in question, I get a cursor that can edit the textbox instead of getting a combobox.

In order to get the combobox. I have to click multiple times in the area indicated with red in the attached pictures. The first picture shows the cell being editable with a cursor, while the second image has the combobox (though masked) after I have clicked multiple times in the red area indicated.

Cursor Editing at a place where a combobox was supposed to beRed area where I click multiple times for the combobox to appear

Upvotes: 1

Views: 600

Answers (2)

msmechanized
msmechanized

Reputation: 436

So I have found the problem. I have converted the

<DataGridTemplateColumn.CellTemplate>
     <DataTemplate>
         <TextBox Text ="{Binding name, Mode=TwoWay}" />
     </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

to

<DataGridTemplateColumn.CellTemplate>
     <DataTemplate>
         <TextBlock Text ="{Binding name, Mode=TwoWay}" />
     </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

This defaults to the desired behavior. I have a feeling that I got the inconsistent behavior because the TextBox can be edited while the Textblock cannot. Therefore a single click would select the TextBox but not revert to the cell editing template.

Upvotes: 1

Robert Harvey
Robert Harvey

Reputation: 180908

I have essentially the same XAML you posted in my code. However, my XAML also includes the following as part of the Combo Box:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <helpers:TakeFocusAction />
    </i:EventTrigger>
</i:Interaction.Triggers>

Its purpose is to put the focus into the combo box whenever the CellEditingTemplate kicks in.

The TakeFocus action looks like this:

using System.Windows;
using System.Windows.Interactivity;

namespace Helpers
{
    public class TakeFocusAction : TriggerAction<UIElement>
    {
        protected override void Invoke(object parameter)
        {
            AssociatedObject.Focus();
        }
    }
}

You'll need the following namespaces in your Xaml:

xmlns:helpers="clr-namespace:Helpers"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

If you don't already have it, you'll need the Microsoft.Xaml.Behaviors.Wpf Nuget package, which provides the interactivity namespace above.

Upvotes: 0

Related Questions