mgilbert65
mgilbert65

Reputation: 75

WPF Checkbox check moves on scrolling

I have a datagrid with the first column being a DataGridTemplateColumn of type Checkbox.

<DataGridTemplateColumn Header="Select">
     <DataGridTemplateColumn.CellTemplate>
           <DataTemplate >
                 <CheckBox  Name="chkSelectForMassRequest" Tag="{Binding AcctNum}" IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" ClickMode="Press" Unchecked="chkSelectForMassRequest_Checked" Checked="chkSelectForMassRequest_Checked" ></CheckBox>
            </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

The strange thing is that when the user checks a few checkboxes and then scrolls down through the data grid, some of the check marks disappear from the original checkboxes and reappear in the newly visible rows even though the user did not check them. My question is, how do I preserve the check marks in all rows regardless if the row is visible or not. And, how do I prevent check marks from moving around on scrolling?

Thanks in advance, Mark

Upvotes: 2

Views: 2583

Answers (5)

M Post
M Post

Reputation: 3

If you want to keep the DataGrid virtualization while also fixing the issue, you can add an event to the DataGrid's scroll event handler which deselects the selected cells and items during scrolling and reselects them after scrolling as stopped for a duration. An example follows below.

You can add the following event to the DataGrid's PreviewMouseWheel event handler:

private DispatcherTimer scrollFinishTimer;
private List<object> previouslySelectedItems = new List<object>();
private List<DataGridCellInfo> previouseSelectedCells = new List<DataGridCellInfo>();
private DataGrid grid;

private void grid_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
    // When scrolling starts
    if (!scrollFinishTimer.IsEnabled)
    {
        // Save the currently selected items
        previouslySelectedItems.Clear();
        foreach (var item in grid.SelectedItems)
        {
            previouslySelectedItems.Add(item);
        }        
        if (grid.SelectionUnit != DataGridSelectionUnit.FullRow)
        {
            foreach(var item in grid.SelectedCells)
            {
                previouseSelectedCells.Add(item);
            }
        }
        grid.UnselectAllCells();
        grid.UnselectAll();
    }

    // Reset the timer every time the event is triggered
    scrollFinishTimer.Stop();
    scrollFinishTimer.Start();
}

With grid defined either in the code behind or in your custom grid class. The scrollFinishTimer should be defined like so

scrollFinishTimer = new DispatcherTimer
{
    Interval = TimeSpan.FromMilliseconds(200) // Or whatever time you prefer.
};
scrollFinishTimer.Tick += ScrollFinishTimer_Tick;

with ScrollFinishTimer_Tick as:

private void ScrollFinishTimer_Tick(object sender, EventArgs e)
{
    // When the timer ticks, consider scrolling finished.
    scrollFinishTimer.Stop();

    // Reselect the previously selected items and cells if they're still valid
    foreach (var item in previouslySelectedItems)
    {
        if (grid.Items.Contains(item))
        {
            grid.SelectedItems.Add(item);
        }
    }

        if (grid.SelectionUnit != DataGridSelectionUnit.FullRow)
        {
            foreach (var cell in previouseSelectedCells)
            {
                if (!grid.SelectedCells.Contains(cell))
                {
                    grid.SelectedCells.Add(cell);
                }
            }
        }
}

Upvotes: 0

Vic
Vic

Reputation: 1

If you have checkbox in a row alignment, you could try add EnableColumnVirtualization="False" EnableRowVirtualization="False" in the XAML that declares the DataGrid

ex.

DataGrid x:Name="here" EnableColumnVirtualization="False" EnableRowVirtualization="False"

Upvotes: 0

CoRe23
CoRe23

Reputation: 151

I was able to solve it with Mode='TwoWay' and UpdateSourceProtepry='PropertyChange'

 <DataTemplate>
<CheckBox IsChecked="{Binding Yes,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center"/>
</DataTemplate>

Upvotes: 2

shodson
shodson

Reputation: 65

I tried changing the VirtualizationMode also but that didn't work for me. I just turned off virtualization entirely and that's what got rid of the problem entirely.

EnableColumnVirtualization="False" and EnableRowVirtualization="False"

Upvotes: 2

Dean Chalk
Dean Chalk

Reputation: 20471

This is because the DataGrid has virtualization switched on by default which is conflicting with your UpdateSourceTrigger directive within your Binding.

Either remove the UpdateSourceTrigger and make the binding TwoWay, or add 'VirtualizingStackPanel.VirtualizationMode="Standard"' in the XAML that declares the DataGrid

Upvotes: 0

Related Questions