1

I made datagrid based on wpf datagrid. I use recycling virtualization and after scrolling shows some cells in random order. When i changed one cell all ok, but when i scrolling to end of datagrid, return back and trying to change one cell, another one is changed.code sample below

Could you help me resolve this problem?

Collections of cells templates:

                <gridColumns:CTemplateContainer
                        CellTemplate="{StaticResource GenericCellTemplate}"
                        CellEditingTemplate="{StaticResource GenericCellTemplate}"/>
                <gridColumns:CTemplateContainer
                        Key="Comment"
                        CellTemplate="{StaticResource GenericCellTemplate}"
                        CellEditingTemplate="{StaticResource CellEditTemplate}"/>
                <gridColumns:CTemplateContainer
                        Key="Checked"
                        CellTemplate="{StaticResource GenericCellCheckedTemplate}"
                        CellEditingTemplate="{StaticResource GenericCellCheckedTemplate}"/>

            </gridColumns:ContainerCollection>

        </grid:DataGridExtended.TemplateContainers>

Templates:

                <TextBlock Text="{Binding Path=Value, Mode=TwoWay}" >
                    <TextBlock.Resources>
                        <Style TargetType="TextBlock" BasedOn="{StaticResource stlTextDefaultBinding}">
                        </Style>
                    </TextBlock.Resources>
                </TextBlock>
            </Border>
        </DataTemplate>

        <DataTemplate x:Key="CellEditTemplate">
            <TextBox Focusable="True" FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
                    DataContext="{TemplateBinding DataContext}"
                    Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                    ValidatesOnDataErrors=True,
                    NotifyOnValidationError=True}"
                    Tag="{TemplateBinding Tag}" BorderThickness="0" Padding="0">
            </TextBox>
        </DataTemplate>

Column code

`class CDataGridTemplateColumn : ctrWPF.DataGridTemplateColumn { private Binding ItemContentBinding;

    public CDataGridTemplateColumn(object header, string path, CTemplateContainer container)
    {
        Header = header;

        var binding = new Binding();
        binding.Path = new PropertyPath("Cells[" + path + "]");

        Binding = binding;

        FillTemplates(container);
    }

    public CDataGridTemplateColumn(ctrWPF.DataGridColumn col, string path, CTemplateContainer container)
    {
        try
        {
            var binding = new Binding() { Mode = BindingMode.TwoWay };
            binding.Path = new PropertyPath(path);
            Binding = binding;

            FillTemplates(container);

            CGridColumnHelper.InitBaseColumn(this, col);
        }
        catch (Exception ex)
        { }
    }

    private void FillTemplates(CTemplateContainer container)
    {
        CellTemplate = container.CellTemplate;
        CellEditingTemplate = container.CellEditingTemplate;
        CellEditingTemplateSelector = container.TemplateSelector;

        if (container.CellStyle == null)
            return;

        CellStyle = container.CellStyle;
    }

    public void InitBinding()
    {
        if (BindingColumn == null)
            throw new ArgumentNullException("BindingColumn null");

        ItemContentBinding = new ctrWPFData.Binding("Cells[" + BindingColumn.Index + "].Value");
    }

    #region Binding

    private BindingBase _binding;

    protected virtual void OnBindingChanged(BindingBase oldBinding, BindingBase newBinding)
    {
        base.NotifyPropertyChanged("Binding");
    }

    public virtual BindingBase Binding
    {
        get
        {
            return this._binding;
        }
        set
        {
            if (this._binding != value)
            {
                BindingBase oldBinding = this._binding;
                this._binding = value;
                base.SortMemberPath = ((Binding)value).Path.Path + ".Value";
                this.ClipboardContentBinding = new Binding(((Binding)value).Path.Path + ".Value");
                base.CoerceValue(DataGridColumn.SortMemberPathProperty);
                this.OnBindingChanged(oldBinding, this._binding);
            }
        }
    }

    private void InitValidation(BindingBase binding)
    {
        Binding _bind = binding as Binding;

        if (_bind == null)
            return;

        _bind.NotifyOnValidationError = true;
        _bind.ValidatesOnDataErrors = true;
        _bind.ValidatesOnNotifyDataErrors = true;
    }

    public override BindingBase ClipboardContentBinding
    {
        get
        {
            return (base.ClipboardContentBinding ?? this.Binding);
        }
        set
        {
            base.ClipboardContentBinding = value;
        }
    }

    private DataTemplate ChooseCellTemplate(bool isEditing)
    {
        DataTemplate template = null;
        if (isEditing)
        {
            template = this.CellEditingTemplate;
        }
        if (template == null)
        {
            template = this.CellTemplate;
        }
        return template;
    }

    private DataTemplateSelector ChooseCellTemplateSelector(bool isEditing)
    {
        DataTemplateSelector templateSelector = null;
        if (isEditing)
        {
            templateSelector = this.CellEditingTemplateSelector;
        }
        if (templateSelector == null)
        {
            templateSelector = this.CellTemplateSelector;
        }
        return templateSelector;
    }

    protected override FrameworkElement GenerateEditingElement(System.Windows.Controls.DataGridCell cell, object dataItem)
    {
        return this.LoadTemplateContent(true, dataItem, cell);
    }

    protected override FrameworkElement GenerateElement(System.Windows.Controls.DataGridCell cell, object dataItem)
    {
        return this.LoadTemplateContent(false, dataItem, cell);
    }

    private void ApplyBinding(DependencyObject target, DependencyProperty property)
    {
        BindingBase binding = this.Binding;
        if (binding != null)
        {
            BindingOperations.SetBinding(target, property, binding);
        }
        else
        {
            BindingOperations.SetBinding(target, property, new Binding());
        }
    }

    private FrameworkElement LoadTemplateContent(bool isEditing, object dataItem, System.Windows.Controls.DataGridCell cell)
    {
        DataTemplate template = this.ChooseCellTemplate(isEditing);
        DataTemplateSelector templateSelector = this.ChooseCellTemplateSelector(isEditing);

        if ((template == null) && (templateSelector == null))
        {
            return null;
        }


        ContentPresenter contentPresenter = new ContentPresenter();

        this.ApplyBinding(contentPresenter, ContentPresenter.ContentProperty);

        contentPresenter.ContentTemplate = template;
        contentPresenter.ContentTemplateSelector = templateSelector;
        contentPresenter.Name = "TEST";
        return contentPresenter;
    }

    #endregion
}

`

1 Answers1

1

I know this thread is quite old and you have probably found an answer now, but it could help other people. I had the same issue while creating a custom filterable datagrid, and changing the virtualization mode (in xaml, in the datagrid properties) fixed it.

VirtualizingStackPanel.VirtualizationMode="Standard"

What's happening here is that the default value (Recycling) reuses the containers, and in some cases the binding fails to update UI. Going for Standard virtualizationMode force to regenerate cells. (It have performance impact).

See this link for more details :VirtualizationMode

Yannick
  • 41
  • 3