Wednesday, September 19, 2018

XamDataGrid SelectedItem bug

I came across this bug with the XamDataGrid today. The problem is the SelectedItem's setter is called with the wrong value when the user sets focus to an editable control in the grid.

Start a new WPF project and call it XamDataGridBadSelector. Add the Infragistics assemblies to the references.

The XAML and code behind are fairly simple.

<Window x:Class="XamDataGridBadSelector.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:XamDataGridBadSelector"
        xmlns:igDP="http://infragistics.com/DataPresenter"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <StackPanel Orientation="Vertical">
        <igDP:XamDataGrid DataSource="{Binding Parents}" SelectedDataItem="{Binding SelectedItem}" GroupByAreaLocation="None" Height="250">
            <igDP:XamDataGrid.FieldLayoutSettings>
                <igDP:FieldLayoutSettings SelectionTypeRecord="Single" AutoGenerateFields="False"/>
            </igDP:XamDataGrid.FieldLayoutSettings>
            <igDP:XamDataGrid.FieldSettings>
                <igDP:FieldSettings AllowSummaries="False" AllowEdit="False"/>
            </igDP:XamDataGrid.FieldSettings>
            <igDP:XamDataGrid.FieldLayouts>
                <igDP:FieldLayout Description="Parents" Key="Parents">
                    <igDP:TextField Label="Parent" Name="Description"/>
                    <igDP:Field Label="" Name="Children"/>
                </igDP:FieldLayout>
                <igDP:FieldLayout ParentFieldLayoutKey="Parents" ParentFieldName="Children">
                    <igDP:FieldLayout.Fields>
                        <igDP:CheckBoxField Label="Smart" Name="IsChecked">
                            <igDP:CheckBoxField.Settings>
                                <igDP:FieldSettings AllowEdit="True"/>
                            </igDP:CheckBoxField.Settings>
                        </igDP:CheckBoxField>
                        <igDP:TextField Label="Child" Name="Description"/>
                    </igDP:FieldLayout.Fields>
                </igDP:FieldLayout>
            </igDP:XamDataGrid.FieldLayouts>
        </igDP:XamDataGrid>
        <TextBlock Text="{Binding SelectedItem.Description, StringFormat='Selected Parent is {0}'}"/>
    </StackPanel>
</Window>


---------------------------------------------------------------------------

using System;

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;

namespace XamDataGridBadSelector
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public class cItem
        {
            public bool IsChecked { get; set; }
            public string Description { get; set; }
            public List<cItem> Children { get; set; }
        }

        public List<cItem> Parents { get; set; }
        private cItem _SelectedItem;
        public cItem SelectedItem
        {
            get { return _SelectedItem; }
            set { _SelectedItem = value; NotifyPropertyChanged("SelectedItem"); }
        }

        public MainWindow()
        {
            Parents = new List<cItem>() { new cItem() {Description="Parent A",
                Children = new List<cItem> { new cItem() { Description="Child A1"},
                                             new cItem() { Description="Child A2" }
                                           } },
                new cItem() {Description="Parent B",
                Children = new List<cItem> { new cItem() { Description="Child B1"},
                                             new cItem() { Description="Child B2" }
                                           }
            } };
            InitializeComponent();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}

Run the project and perform the following steps...
1. Click on "Parent B". You will see the selected parent is Parent B
2. Expand Parent A. Note that the selected parent is still Parent B
3. Click on the check box for Child A1. The selected parent is now nothing.


If you put a breakpoint on the SelectedItem setter you will see it is called with a value of Null when you click directly on the check box and it is never called with a value of "Child A1"

There is a partial workaround for this.

Change the field settings to look like this...
<igDP:FieldSettings AllowSummaries="False" AllowEdit="False" CellClickAction="SelectRecord"/>

This causes the setter to be called correctly but requires the user to click the checkbox twice to change its value. The second click calls the SelectedItem's setter with a Null value.


Update: To my great pleasure I received an intelligent response from Infragistics that enabled me to understand and solve this problem. Essentially it seems I should be tracking the ActiveItem instead of the SelectedItem. All I have to do is change SelectedDataItem="{Binding SelectedItem}" to ActiveDataItem="{Binding SelectedItem}". OK - I should probably rename the property but you get the idea. Make the change and try it yourself.


Once you have the correct child it's easy to implement a child-to-parent link and retrieve the active parent.

No comments:

Post a Comment