RowDetails with a sub DataGrid : Weird events behaviour !

Nov 11, 2008 at 5:40 PM
Edited Nov 11, 2008 at 6:01 PM
Hi,

I want to display a list of file.
For each file, then I display another grid, that contain various information for that file.

So far, so good. In my subgrid (the grid that displays file information), I have a Combo box.
So far, so good. The combo displays correctly. However, the selectionChanged events comes when i OPEN the combox but NEVER when an item is selected in the combobox !

If I move the combox in the primary grid, event behaviour is fine. It seems that the Combo's event handler is disturbed with the 2nd grid (the one belonging to the Row Details).
Some code extract:

   <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>

        <toolkit:DataGrid Grid.Row="0" Name="tagGrid" AutoGenerateColumns="False" CanUserAddRows="False">
            <toolkit:DataGrid.Columns>

                <!-- Display the name of the file -->
                <toolkit:DataGridTextColumn Header="Image" Width="SizeToCells"  
                                           Binding="{Binding Path=DiskPath}"
                                           IsReadOnly="True"/>

            </toolkit:DataGrid.Columns>

            <toolkit:DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <toolkit:DataGrid ItemsSource="{Binding Path=KeywordsForPicture}" AutoGenerateColumns="False" CanUserAddRows="False">
                        <toolkit:DataGrid.Columns>
                            <toolkit:DataGridCheckBoxColumn Header="Utiliser"
                         Binding="{Binding Path=TagIt}"/>

                            <toolkit:DataGridTextColumn Header="Tag" Width="SizeToCells"  
                                           Binding="{Binding Path=TagName}"
                                           IsReadOnly="False"/>
                            <toolkit:DataGridTemplateColumn Header="Catégorie">
                                <toolkit:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Path=CatName}"/>
                                    </DataTemplate>
                                </toolkit:DataGridTemplateColumn.CellTemplate>
                                <toolkit:DataGridTemplateColumn.CellEditingTemplate>
                                    <DataTemplate>
                                        <ComboBox IsEditable="False"
                       SelectedItem="{Binding Path=CatName}"
                       Tag="{Binding Path=.}"
                       ItemsSource="{Binding Source={StaticResource Categorieslookup}}"
                       SelectionChanged="ComboBox_SelectionChanged"     =====> ISSUE : We enter the handler when the combo is opened, never when an item is selected in the combo !!!!!
                        />
                                    </DataTemplate>
                                </toolkit:DataGridTemplateColumn.CellEditingTemplate>

                            </toolkit:DataGridTemplateColumn>
                        </toolkit:DataGrid.Columns>
                    </toolkit:DataGrid>
                </DataTemplate>
            </toolkit:DataGrid.RowDetailsTemplate>
        </toolkit:DataGrid>

        <Button Name="valid_btn" Click="valid_btn_Click" Grid.Row="1">Ok</Button>
    </Grid>


Then I have tried another variation, same issue : Combox doesn't update when an item is selected !!

   <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>

        <toolkit:DataGrid Grid.Row="0" Name="tagGrid" AutoGenerateColumns="False" CanUserAddRows="False">
            <toolkit:DataGrid.Columns>

                <!-- Display the name of the file -->
                <toolkit:DataGridTextColumn Header="Image" Width="SizeToCells"  
                                           Binding="{Binding Path=DiskPath}"
                                           IsReadOnly="True"/>

            </toolkit:DataGrid.Columns>

            <toolkit:DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <toolkit:DataGrid ItemsSource="{Binding Path=KeywordsForPicture}" AutoGenerateColumns="False" CanUserAddRows="False">
                        <toolkit:DataGrid.Columns>
                            <toolkit:DataGridCheckBoxColumn Header="Utiliser"
                         Binding="{Binding Path=TagIt}"/>

                            <toolkit:DataGridTextColumn Header="Tag" Width="SizeToCells"  
                                           Binding="{Binding Path=TagName}"
                                           IsReadOnly="False"/>
                            <toolkit:DataGridComboBoxColumn Header="Categorie" SelectedItemBinding="{Binding Path=CatName}"
                                                            ItemsSource="{Binding Source={StaticResource Categorieslookup}}" />
                        </toolkit:DataGrid.Columns>
                    </toolkit:DataGrid>
                </DataTemplate>
            </toolkit:DataGrid.RowDetailsTemplate>
        </toolkit:DataGrid>

        <Button Name="valid_btn" Click="valid_btn_Click" Grid.Row="1">Ok</Button>
    </Grid>

With this one, combo is set with the right value, I can use the drop-down but when I choose an Item, there is no updated : CatName still has the previous value !!!


Why ?
Thanks.



Coordinator
Nov 13, 2008 at 2:20 PM
This is a known bug and is b/c the ComboBox popup in the RowDetails template is rendered on top of another row and the other row steals the click input.  There is no easy workaround for it.  You can listen to the PreviewMouseLeftButtonDown event and cancel the event if you know that the combobox is open and you want to select an item but it will be a really big hack.
Nov 13, 2008 at 5:09 PM
I see the idea...Nice hack ! Anyway, I've changed my UI to workaround this...

I hope they'll fix it in a later version. Or add grouping also...

Thanks for your answer.
Nov 16, 2008 at 10:53 PM
Hi Vinsibal,

I wonder have you got a sample for this kind of hack in action? The scenario of using a combobox in row detail is very common ....

Thanks
Feb 6, 2009 at 8:18 AM
Edited Feb 6, 2009 at 9:17 AM
I have got the same Problem. When I click into the Combobox nothing gets selected and the underlaing row is opened :-\
Same with the DatePicker Control!

I installed the new Realease (January 2009) and it's not fixed yet. Any information on this? Is there somebody working on a fix?
I did not yet startes working on a workaround. Hope somebody has an Info before I spend many hours working around it...

Edit:
The workaround for the Comboboxes was very easy! Here some code snippets:
XAML:
<ComboBox Margin="3" HorizontalAlignment="Left" VerticalAlignment="Top"
                    DropDownOpened="SelectionHack_DropDownOpening"
                     DropDownClosed="SelectionHack_DropDownClosing" .../>

C#: When the Dropdown opens the _isOpened is set to true. When you click on a value in the combobox the DataGrid fires the PreviewMouseLeftButtonDown, there is Called the Method SelectionHack_MouseLeftButtonDownCanceler. if _isOpened is true the Event is canceled otherwise happens nothing.

    private void SelectionHack_DropDownOpening(object sender, EventArgs e)
        {
            _isOpened = true;
        }

        private void SelectionHack_DropDownClosing(object sender, EventArgs e)
        {
            _isOpened = false;
        }

        private void SelectionHack_MouseLeftButtonDownCanceler
                    (object sender,  MouseButtonEventArgs e)
        {
            if (_isOpened)
            {
                e.Handled = true;
                _isOpened = false;
            }
        }

This is working fine for Comboboxes but not with the DatePicker. Any suggestions?

Feb 6, 2009 at 9:28 AM

Hi,

I don't remember where I have seen a workaround for this and I guess it was on CodePlex forums.
Add a callback when an item is selected then look in the visual tree of the grid to locate your control and then play with e.Handled event... Someone posted a little example. Quite kludgy...

On my side, I did change my UI not to use the grid control anymore..






> Message du 06/02/09 10:18
> De : "Woggly"
> A : xpouyollon@orange.fr
> Copie à :
> Objet : Re: RowDetails with a sub DataGrid : Weird events behaviour ! [wpf:39696]
>
>

> From: Woggly

I have got the same Problem. When I click into the Combobox nothing gets selected and the underlaing row is opened :-\
> Same with the DatePicker Control!
>
> I installed the new Realease (January 2009) and it's not fixed yet. Any information on this? Is there somebody working on a fix?
> I did not yet startes working on a workaround. Hope somebody has an Info before I spend many hours working around it...

> Read the full discussion online.

> To add a post to this discussion, reply to this email (wpf@discussions.codeplex.com)

> To start a new discussion for this project, email wpf@discussions.codeplex.com

> You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

> Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com


Jun 1, 2009 at 10:50 AM
Edited Jun 1, 2009 at 11:07 AM

Hi,

The Same Scenario i am also working,

but instead of combo box i call another xaml as popup window.

In the POPUP window i have another datagrid. when i press mouse left button up on the popup page, event triggers to

<Binding.ValidationRules>
           <OnValidation:OnClassValidationRules ValidationStep="UpdatedValue"/>
</Binding.ValidationRules>

Actually i trying to do validation on row level. When i press the mouse it triggers to validation class, before its takes the value from the datagrid of popup page

 

Sample Code:

<Custom:DataGridTemplateColumn Header="Class" MinWidth="145">
                                <Custom:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <!--<TextBlock Text="{Binding Path=CLASS, Mode=TwoWay}"  HorizontalAlignment="Left">-->
                                        <TextBlock>
                                            <TextBlock.Text>
                                                <Binding Path="CLASS" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
                                                    <Binding.ValidationRules>
                                                        <OnValidation:OnClassValidationRules ValidationStep="UpdatedValue"/>
                                                    </Binding.ValidationRules>
                                                </Binding>
                                            </TextBlock.Text>
                                        </TextBlock>
                                    </DataTemplate>
                                </Custom:DataGridTemplateColumn.CellTemplate>
                                <Custom:DataGridTemplateColumn.CellEditingTemplate >
                                    <DataTemplate>
                                        <Button x:Name="BTN_Class_PopUp" Content=".." Style="{DynamicResource button-glossy}"
                                                Template="{DynamicResource btn_save}" HorizontalAlignment="Right"
                                                Width="20" Click="BTN_Class_PopUp_Click"/>
                                    </DataTemplate>
                                </Custom:DataGridTemplateColumn.CellEditingTemplate>
                           </Custom:DataGridTemplateColumn>

on BTN_Class_PopUp_Click i open the another xaml as popup. when you mouse left button up, it's not triggering to mouse event.

Step 1:

        Dim ClassDs As New DataSet
        ClassDs = StoreP.getDataX("*", "*")
        FrmPopUpClass = New ClassPopup
        Dim mode As System.Windows.Data.Binding = New Binding(ClassDs.Tables(0).Columns(2).ColumnName)
        mode.Mode = BindingMode.TwoWay
        FrmPopUpOccupationCategory.PopUpOnItemName = "CLASS"
        CType(FrmPopUpClass .Occup_Grid.Columns(0), DataGridTextColumn).Binding = mode
        FrmPopUpClass.AutoGenerateColumns = False
        FrmPopUpClass.AreRowDetailsFrozen = True
        FrmPopUpClass.CanUserAddRows = False
        FrmPopUpClass.ItemsSource = Nothing
        FrmPopUpClass.Items.Clear()
        FrmPopUpClass.ItemsSource = CLassDs.Tables(0).DefaultView
        MyPopUp.Child = FrmPopUpClass
        MyPopUp.IsOpen = True

Step 2:

mouseleftbuttonup: PopUp xaml

 Dim drv As DataRowView

drv =dgGrid.SelectedItem
            Dim SelectedItem As String = ""
            If PopUpOnItemName = "CLASS" Then
                SelectedItem = drv.Item("CLASS")
            End If
            RaiseEvent DataCollected(SelectedItem)

Step 3:

Private Sub FrmPopUpClass_DataCollected(ByVal CLASS As String) Handles FrmPopUpClass.DataCollected
       Dim drv As DataRowView = Dg_5_class.SelectedItem
        drv.Item(0) = CLASS
        Dg_5_class.SelectedItem = drv
       MyPopUp.IsOpen = False
    End Sub

step 4:

 

Public Class OccupationClassAndSumCoveredLinkSettings
        Inherits ValidationRule

Public Overloads Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As ValidationResult
           ' if this rule is being applied to a cell we will be inspecting a binding expression
            If TypeOf value Is BindingExpression Then
                ' obtain the row which is being validated
                Dim expression As BindingExpression = TryCast(value, BindingExpression)
                Dim row As DataRow = DirectCast(expression.DataItem, DataRowView).Row

                ' determine the column to validate
                Dim propertyName As String = expression.ParentBinding.Path.Path

                Return ValidateColumn(propertyName, row)

                ' if this rule is being applied to a cell we will be inspecting a binding group
            ElseIf TypeOf value Is BindingGroup Then
                Dim group As BindingGroup = DirectCast(value, BindingGroup)

                ' iterate over all the bound items (this should always be one!)
                For Each item As Object In group.Items
                    Dim row As DataRow = DirectCast(item, DataRowView).Row

                    ' validate against the metadata for each column
                    For Each column As DataColumn In row.Table.Columns
                        Dim result As ValidationResult = ValidateColumn(column.ColumnName, row)
                        If result <> ValidationResult.ValidResult Then
                            Return result
                        End If
                    Next
                Next
                'Dim dv As DataView = DirectCast(value, BindingGroup)

                'For Each Item As Object In group.Items

                'Next
            End If

            Return ValidationResult.ValidResult
        End Function

        Private Function ValidateColumn(ByVal columnName As String, ByVal row As DataRow) As ValidationResult

                    doing some validation here..

        End Function

End Class

it trigger to   <OnValidation:OnClassValidationRules ValidationStep="UpdatedValue"/> class.

 

Actually processing steps should as above.

But,

It happens as

step 1: then

step 4: then

step 2: then

step 3:

Please advice me where i am doing mistake on it.

Please help on this (I'm new to wpf)

Regards,

Prabakaran S.