How to set all row heights of wpf datagrid when setting single row height

I am using wpf datagrid and I am looking for a way to set the height in all rows when the user configures one of them. I know the datagrid has a RowHeight property that sets all the row heights at once, but the way of catching the individual row height makes me feel faster.

+2


source to share


4 answers


I came to this through trial and error, so long ass, you are using the ItemsSource, it should work fine. It should work with virtual rows and only cause a short visual pause and it toggles (this is mainly due to autogenerating columns, so it can be avoided).

Like hacks, it has the advantage of simplicity and use of mechanics that are not expected to change.



The custom action trigger heuristic could be improved, but it hasn't triggered yet.

using Microsoft.Windows.Controls;
using Microsoft.Windows.Controls.Primitives;

public static class DataGridExtensions
{
    public static void LinkRowHeightsToUserChange(this DataGrid dataGrid)
    {
        double? heightToApply = null;
        bool userTriggered = false;

        if (dataGrid.RowHeaderStyle == null)
            dataGrid.RowHeaderStyle = new Style(typeof(DataGridRowHeader));
        if (dataGrid.RowStyle == null)
            dataGrid.RowStyle = new Style(typeof(DataGridRow));

        dataGrid.RowStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRow.SizeChangedEvent,
            Handler = new SizeChangedEventHandler((r, sizeArgs) =>
            {
                if (userTriggered && sizeArgs.HeightChanged)
                        heightToApply = sizeArgs.NewSize.Height;
            })
        });
        dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRowHeader.PreviewMouseDownEvent,
            Handler = new MouseButtonEventHandler(
                (rh,e) => userTriggered = true)
        });
        dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRowHeader.MouseLeaveEvent,
            Handler = new MouseEventHandler((o, mouseArgs) =>
            {
                if (heightToApply.HasValue)
                {
                    userTriggered = false;
                    var itemsSource = dataGrid.ItemsSource;
                    dataGrid.ItemsSource = null;
                    dataGrid.RowHeight = heightToApply.Value;
                    dataGrid.ItemsSource = itemsSource;
                    heightToApply = null;
                }
            })
        });
    }

      

+2


source


There are no events that could be used directly for this. What you can do is use another event that fires when rows are resized and other things. The event I'm currently thinking about is PreviewMouseUp, which is the release when you release the mouse button anywhere if you are a datagrid.



What you can do is when you fire the event, you can check the line height of all your lines and find another one and then update all the lines.

+3


source


@Aran

Do you remember what it is?

I can tell you: if you delete both lines to undo and reset the source of the elements (which really slows down the whole process quite a bit), the size of the line you resize will have the final height set.

It seems that when you resize a row, you change its height directly, and that overrides whatever value you set for the dataGrid RowHeight property for that row, in particular. So, basically, this is what you can get:

dataGrid RowHeight = 20

you change the height of one row (say 5th) to 30 => this row Height is set to 30, and the dataGrid RowHeight is set to 30. Everything looks good so far.

now, change another row Height to 20 (say 2nd row). you set this row height to 20 and DataGrid'RowHeight to 20, which will put all other rows at 20, EXCEPT the 5th row, which remains at 30. (since it was forced to that value before)

emptying the source and resetting it forces each reloaded row to respect the dataGrid RowHeight account, which fixes the problem.

+2


source


As far as I know, there is no event that is raised when the row is resized.

My first suggestion was to set the RowStyle to create a binding (OneWay) between the DataGridRow height property and the datagrid RowHeight property, but if you check the row height after changing it, it won't change, ActualHeight is the property that contains the row "actual "the height when it was resized and ActualHeight could not be set because" it has no accessory set available. "

After that I thought: where does DataGridRow ActualHeight get its value from?

I remembered this post , which explains how to determine which cell and row was clicked, and also displays the default visual template tree for the DataGrid.

Through trial and error (using the visual tree image in the link above) I found that it was the DataGridCellPresenter that saved the height that was used (actually I'm not 100% sure, this was the first class, the height of the visual tree was changed from the DataGridCell).

Apparently the DataGrid does not provide an API to get the DataGridCellsPresenter from the DataGridRow (as I found out here )

So my first approach was to get all DataGridCellPresenter in the DataGrid (via the visual tree) after it was populated and programmatically create a binding between the Height property of the DataGridPresenter and the RowHeight property of the DataGrid.

Here is the code for that (my DataGrid instance name is dataGrid1):

Getting the whole DataGridCellPresenter:

    void GetAllDataGridCellPresenters(DependencyObject parent, List<DataGridCellsPresenter> presenters) 
    {
        int numberOfChildren = VisualTreeHelper.GetChildrenCount(parent);         
        for (int i = 0; i < numberOfChildren; i++)
        {
            if (VisualTreeHelper.GetChild(parent, i) is DataGridCellsPresenter)
            {
                presenters.Add(VisualTreeHelper.GetChild(parent, i) as DataGridCellsPresenter);
            }
            else if (VisualTreeHelper.GetChild(parent, i) != null)
            {
                GetAllDataGridCellPresenters(VisualTreeHelper.GetChild(parent, i), presenters);
            }
            else
                return;
        }
    }

      

Set up bindings programmatically for all of them (call this when the Loaded event is raised by the DataGrid):

    void SetBindingInDataGridPresenter()
    {
        List<DataGridCellsPresenter> presenters = new List<DataGridCellsPresenter>();
        GetAllDataGridCellPresenters(dataGrid1, presenters);
        foreach (DataGridCellsPresenter presenter in presenters)
        {    
            Binding binding = new Binding("RowHeight");
            binding.Source = dataGrid1;
            binding.Mode = BindingMode.TwoWay;
            presenter.SetBinding(DataGridCellsPresenter.HeightProperty, binding);
        }
    }

      

(Note: setting the binding as OneWayToSource didn't work, I really don't know why, I probably don't see anything obvious here ...)

It actually worked ... sort of ... because I used the visual tree to get the DataGridCellsPresenter. I only got the visible: P, but it shows that it can be done this way.

So, finally, the correct way to do this is to provide a DataGrid control template, it can be the same as the default, except for the HeightGridCellsPresenter Height property data bound to the DataGrid RowHeight property.

I know it doesn't show exactly how to do this, but you just have to learn (same as I did: P) override the control pattern ; somehow get the default DataGrid template (or if you are already using another, then great, you probably know more than me about this, and already know how to do this to get the DataGridCellsPresenter Height property automatically associated with the property RowHeight DataGrid) and change it to this bit of magic that binds both height properties.

+1


source







All Articles