microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.35k stars 678 forks source link

Discussion: Modern WinUI DataGrid - Input Needed #1500

Closed anawishnoff closed 11 months ago

anawishnoff commented 5 years ago

Discussion: Modern WinUI DataGrid

Hey community members! We've seen that DataGrid has been a valuable piece of the Windows Community Toolkit for many of you and we are interested in graduating it to a native WinUI control (!!). I need your help to figure out what would be needed to make a full-scale DataGrid the best it can be.

I want to hear your input on all things DataGrid. To get started, feel encouraged to answer as few or as many questions as you have time for:

  1. What are some wish-list items that you want for DataGrid?
  2. Where can DataGrid improve in terms of UI, UX, and overall design?
  3. What do you like/dislike about DataGrid?
  4. What are some scenarios in which you use DataGrid?
  5. Are there any scenarios that you wish it could fit better into?

Thanks in advance everyone! See below links for some refreshers and context.

Related Links

Read up on the DataGrid documentation Download and interact with DataGrid via the DataGrid Nuget package download Refresh your knowledge by checking out the existing open source DataGrid implementation in the WCT.

mdtauk commented 5 years ago

More viewmodes. Take a look at File Explorer and it's Icon views. The DataGrid should be able to show icons/items in a grid with grouping, as well as the headed rows and columns.

I know this may not be possible, or out of scope - but it is an aspect of WinUI vs Win32 that isn't as easy as 1:1 - and a modern version of File Explorer, or the Common File Dialogs - may have need of such a control. This could be that control, not an internal custom control.

Pinox commented 5 years ago

My wishlist : to me a good datagrid includes all the following features by default. I'm borrowing some screenshots from the html world.

Easy filter the whole page with preferred row count.

1

Select / Deselect Visible Columns , Column Sorting , Copy , Print

2

Export data to specific format.

3

Column Reordering by dragging column.

4

Column Filtering

5

Fixed Header - where header stays on top even when scrolling

Row details with XAML template for details.

6

Row Grouping

7

Drag & Drop Row Order

8

The features above in my opinion should be standard in all datagrids.

If you want to make datagrid stand out to the html world then I would also include the following. I find myself many times looking at a datagrid and then settling on a listview as the datagrid lacks these features.

Sideswipe the row to include features like edit , delete , flag etc.

sideswipe

The above features handle mainly the "presentation of data" , what is still lacking from WinUI is what I believe should be a native WinUI feature (control ) like the Microsoft Pivot Control. to compliment the datagrid.

MS already has the source code for this and it was an absolute awesome control back in the days.

pivot1

https://www.youtube.com/watch?v=ZJIkQ9nebKY

Now you cover the presentation and visualization of data that should be the minimum to set WinUI apart from all the basic features out there.

Most importantly it really displays the power of "native apps" that should include awesome animations and visually appealing controls that is powerful and looks really cool.

I can take this one step further and say after the above features (visualizations) we can include 2D/3D animations that creates a concept of depth in the data and will take us to a different stratosphere , but I guess that is for another day ;))

uwp2

ArchieCoder commented 5 years ago

A good starting point is looking at your partner Telerik with their RadDataGrid (UWP Open Source). With one of my clients, I used it and it actually works well. It is hyper fast and versatile. The only thing that is difficult is their code, there is no way to modify anything from their engine without a good comprehension of the architecture.

I would expect the new DataGrid to be as performant as Telerik.

lukeblevins commented 5 years ago

I'm very glad to see the WinUI team is considering a DataGrid control.

The most substantial improvements I'd like to see from a new control to replace the Toolkit DataGrid:

NoahFeller commented 5 years ago

The option to have an edit button which puts draggable icons next to each row to move the order would be a useful feature. It would also be great to see some shadows behind the row being lifted up and moved (since one of the main Fluent attributes is depth). Small up and down arrows might be good next to the dragging icon to move the rows more easily with mouse input. If a row is moved using the arrows, a subtle sliding animation would be a nice touch. With touch input, the option to hold on a row and just move it without even needing to press the edit button might work well too. I'm not sure if this is already supported, but I could see selection check boxes like in File Explorer making obvious which DataGrids support row selection and just improve the overall UX. The iOS reminders app contains some of these ideas (examples pictured below). The iOS Stocks app also has a similar sort of deal with movable rows. Most of these ideas would also work great for columns.

123456

IMG_1820 (1)

NoahFeller commented 5 years ago

@NoahFeller That type of action makes more sense for a List View. With a Grid view you are not rearranging the order, there should be sort options but the user is not dragging things around.

*Edit After thinking about it a little more, I do see how such an option can be useful. However, I definitely don't think this should be the default behavior.

Yeah you're probably right @yaichenbaum. I was envisioning those suggestions as the ability to do a custom sort and I thought dragging might be useful for that. So I agree, definitely not default but it might be pretty useful as an option. Thanks for the feedback!

LazerPanth3r commented 5 years ago

The simplicity of the WPF datatable to datagrid function. I've actually been fighting for the past week or so trying to get a UWP datagrid to work how I had it in WPF where I could just bind a Datagrid to a Dataview, then fill the Dataview from SQL with a datatable.defaultview. The grid then just displayed the data table. It was amazingly simple to do, and UWP so far has made this ridiculously complicated.

kvarekamp commented 5 years ago

make it cross platform

keeganatorr commented 5 years ago

I would like to request a single cell selection mode, excel style. The ultimate goal being a mode with the exact behaviour as a WinForms DataGridView.

chiefklondog commented 5 years ago

Having an assortment of virtualization options that can support different use cases (From plain scrolling virtualization options like recycling to other concepts like data paging) Often (In similar desktop controls that support this) some of these options begin to fail when used with custom templates for columns with unique data. The more they can support in those cases, the better.

mdtauk commented 5 years ago

If at all possible, the Paging Control #268 proposal, should be synced, and any hooks required be added to the DataGrid control.

robloo commented 5 years ago

This is good news! I've been waiting for something official on the DataGrid front for a while ever since it appeared in the community toolkit. This is really the last control missing from WinUI 3.0 that the community toolkit doesn't have a good alternative for.

First, please, don't reinvent the wheel. As a base start with the WPF implementation of the DataGrid (I know you can't use the code but please use 100% of the API) -- NOT the Silverlight one. The WPF DataGrid was much more feature-complete and has fewer bugs in my testing.

In using the community toolkit DataGrid I also requested the following API additions that came up for various use cases Discussion here:

I also continue to have lots of problems with the community tookit DataGrid resetting the scroll position to the top after ItemsSource is changed. This needs to get fixed so the offset is preserved like in WPF; however, we also need to be able to control this which is why I would suggest the following API as well:

@RBrid Also helped with some analysis here:

verelpode commented 5 years ago

Suggested new events, and some improvements to preexisting events:

Event Comments
ContextRequestedForColumnHeader To support showing a context menu (or other flyout) when a column header is right-clicked. The same as Windows.UI.Xaml.UIElement.ContextRequested but for column headers instead of the entire DataGrid.
ContextCanceledForColumnHeader The same as Windows.UI.Xaml.UIElement.ContextCanceled but for column headers instead of the entire DataGrid.
ContextRequestedForRow To support showing a context menu (or other flyout) when a row is right-clicked. The same as Windows.UI.Xaml.UIElement.ContextRequested but for rows instead of the entire DataGrid.
ContextCanceledForRow The same as Windows.UI.Xaml.UIElement.ContextCanceled but for rows instead of the entire DataGrid.
RowTapped Note also the case of tapping a row that is already selected.
RowDoubleTapped The same as Windows.UI.Xaml.UIElement.DoubleTapped but for rows instead of the entire DataGrid.
RowRightTapped The same as Windows.UI.Xaml.UIElement.RightTapped but for rows instead of the entire DataGrid. See also ContextRequestedForRow.
PointerPressedInRow The same as Windows.UI.Xaml.UIElement.PointerPressed but for rows instead of the entire DataGrid.
PointerReleasedInRow The same as Windows.UI.Xaml.UIElement.PointerReleased but for rows instead of the entire DataGrid.
PointerMovedInRow The same as Windows.UI.Xaml.UIElement.PointerMoved but for rows instead of the entire DataGrid. Possibly PointerMovedInRow would only be triggered while the pointer is captured.
ColumnHeaderTapped Note also the case of tapping a column header that is already selected.
ColumnHeaderDoubleTapped The same as Windows.UI.Xaml.UIElement.DoubleTapped but for column headers instead of the entire DataGrid.
ColumnHeaderRightTapped The same as Windows.UI.Xaml.UIElement.RightTapped but for column headers instead of the entire DataGrid. See also ContextRequestedForColumnHeader.
ColumnHeaderWidthChanged Alternatively could be named ColumnHeaderResized. In the event args, include a boolean property that specifies whether it was changed by the user versus changed programmatically. Obviously the event args should also specify which column header was resized/changed.
SortOrderChanged Should be triggered when the list of selected column headers changes. Also triggered when any of the selected columns is switched between ascending versus descending order. In the event args, include a boolean property that specifies whether the sort order was changed by the user versus changed programmatically. See also preexisting event Sorting. I think a new event SortOrderChanged would be triggered after the Sorting event is triggered, if the sorting isn't cancelled.
Sorting Already exists but consider adding a settable boolean property in event args that allows the sorting request to be cancelled. For example, the sorting may be invalid or unable to be performed and needs to be cancelled. Also add a boolean property to specify whether sorting was requested by the user versus programmatically.
ColumnSortDirectionChanged This event could be created but it could be unnecessary if the aforementioned SortOrderChanged event is created, if SortOrderChanged is also triggered when the sort-direction changes.
ColumnDisplayIndexChanged Already exists but please consider adding a boolean property (in event args) that specifies whether it was changed by the user versus changed programmatically. Also, please document why it's necessary to have both of the ColumnDisplayIndexChanged and ColumnReordered events. Alternatively, eliminate one of these events.
ColumnReordered Already exists but please consider adding a boolean property that specifies whether it was changed by the user versus changed programmatically.
SelectionChanged Already exists but please consider adding a boolean property (in event args) that specifies whether it was changed by the user versus changed programmatically.
CopyingRowClipboardContent Already exists but please consider adding a boolean property to the event args that specifies whether the operation is cut instead of copy. Alternatively make a separate event for cut.
CuttingRowClipboardContent Doesn't exist. Consider making an event that is triggered when user attempts to cut rows (via control-X hotkey, context menu, or otherwise). Alternatively make the aforementioned boolean property that would allow CopyingRowClipboardContent to be triggered for both of copy and cut operatoins
PastingRowClipboardContent Doesn't exist. Consider making an event that is triggered when user attempts to paste (via control-V hotkey, context menu, or otherwise).
dotMorten commented 5 years ago

I think the most important feature for me would be the ability to easily handle a million rows or more, without having to load a millions rows into memory. The ISupportIncrementalLoading interface isn't good enough for this, because the scroll bar only reflects how many rows you have loaded so far (not total count), and to get to row 1 million, you'd have to keep scrolling to the end over and over and load more and more data, and hope I won't run out of memory. But if I know I have 1 million data records, let me tell the datagrid that, and if I scroll fast or jump to the end, I can be asked to just provide the last few rows. Think scrolling through a list of rows in a database that I'll be dynamically pulling in.

jkewley commented 5 years ago

I think the most important feature for me would be the ability to easily handle a million rows or more, without having to load a millions rows into memory. The ISupportIncrementalLoading interface isn't good enough for this, because the scroll bar only reflects how many rows you have loaded so far (not total count), and to get to row 1 million, you'd have to keep scrolling to the end over and over and load more and more data, and hope I won't run out of memory. But if I know I have 1 million data records, let me tell the datagrid that, and if I scroll fast or jump to the end, I can be asked to just provide the last few rows. Think scrolling through a list of rows in a database that I'll be dynamically pulling in.

This.

'Modern' means lightweight and quick, and enterprise apps are commonly about sorting through tons of internal data to find and explore the appropriate records. Paging, sorting, async incremental loading, endless scrolling - all of these are staples of desktop apps which leverage data grids.

MS should produce a sample app which highlights these features in the new grid and collect feedback from enterprise developers over time to make these experiences better. Have it run off of a large dataset like World Wide Importers to demonstrate its effectiveness.

verelpode commented 5 years ago

@dotMorten

I think the most important feature for me would be the ability to easily handle a million rows or more, without having to load a millions rows into memory.

I wish for that as well. In order to assist with supporting a million rows (and I mean assist, not necessarily the complete solution), I suggest that DataGrid should make its current data-binding technique optional. I believe currently data-binding is mandatory (unless my knowledge is no longer up-to-date with the latest version of DataGrid). DataGrid shouldn't require use of Windows.UI.Xaml.Data.Binding as the only supported way of retrieving the values for each cell/column in each visible row.

I suggest that DataGrid allow apps to give DataGrid a delegate or interface instance that DataGrid will invoke whenever DataGrid needs to retrieve the value of a cell/column in a row (alternatively, this delegate or interface could retrieve the entire row -- all column values for a specified row).

Ideally (if possible), DataGrid would allow this delegate or interface to operate asynchronously. For example, the delegate or interface might return a Task or IAsyncOperation<TResult> instead of immediately returning the requested value.

Alternatively, asynchronous support is also possible without Task and IAsyncOperation<TResult>, if DataGrid operates similar to the following procedure:

  1. DataGrid decides that it needs to retrieve the value of cell/column 5 in row ID 50001. Alternatively DataGrid decides to retrieve all column values for row ID 50001.
  2. DataGrid invokes a delegate or interface instance or event handler that notifies the app that DataGrid has requested the loading of the data values of the specified column/row or entire row.
  3. The app retrieves the requested row data asynchronously. For example, it could asynchronously perform an SQL database query.
  4. The app finishes retrieving the requested row data. The app invokes a method in DataGrid that gives the row data to DataGrid.
  5. DataGrid displays the row data, or does whatever else it needed to do with the data.
anawishnoff commented 5 years ago

First off, wow!! Thanks so much to everyone who's contributing their ideas. I have a few specific responses below, but overall I wanted to say that I am saving a ton of these comments and really enjoying hearing how we can build an awesome modern DataGrid. Keep it coming!

@Pinox thanks so much for that detailed response and the screenshots. Your wishlist is awesome (especially those cool animations!) - I agree that those features found in html are a good inspiration point and are simple but would greatly improve quality of life. Will definitely be saving this comment for future reference!

@verelpode, @robloo, @duke7553 YES to DataGrid-specific events! Thank you all for the detail you put into these. As we design for touch-first and for a variety of inputs, events like these should definitely be implemented!

@dotMorten, @jkewley, @verelpode Performance is definitely one of the main motivations for this project and one of the main improvements we want to implement, through a new data virtualization story and the use of modern controls such as ItemsRepeater. Will keep you all updated once we have more specifics - but thanks again for these details youve suggested.

@Laz3rPanth3r, @robloo, @keeganatorr We hear you loud and clear about liking the DataGrids that belong to WPF and other UI frameworks - we are definitely taking this into account in this refresh!

verelpode commented 5 years ago

Thanks for the great work on DataGrid and the request for feedback! Here are a few more suggested enhancements.

Need more subclasses of DataGridColumn

The current subclasses/implementations of DataGridColumn are insufficient. I suggest making the following new subclasses of DataGridColumn:

Proposed Subclass Description
DataGridIconColumn A common requirement is to display an icon in each row of a list, therefore I suggest making a DataGridColumn subclass named DataGridIconColumn that typecasts the retrieved cell value to Windows.UI.Xaml.Controls.IconSource and renders the IconSource instance (a different IconSource instance is rendered in each cell).
DataGridImageColumn DataGridImageColumn should operate the same as the proposed DataGridIconColumn except that it should render Windows.UI.Xaml.Media.ImageSource instead of Windows.UI.Xaml.Controls.IconSource.
DataGridDateTimeColumn Displays date and/or time, depending on settings. Typecasts the cell value to System.DateTimeOffset or System.DateTime (both supported) and converts it to text to be displayed in the cell. The conversion to text should be controlled by formatting settings/properties in the DataGridDateTimeColumn class. Obviously sorting by date/time must also be supported.
DataGridTimeSpanColumn Typecasts the cell value to System.TimeSpan and converts it to text to be displayed in the cell. The conversion to text should be controlled by formatting settings/properties in the DataGridTimeSpanColumn class. Obviously sorting must also be supported, and it must sort the TimeSpan instances not the displayed text.
DataGridDataSizeColumn Typecasts the cell value to System.Int64, UInt64, Int32, or UInt32 (all supported) and converts it to a size-in-bytes (as text) to be displayed. For example, 1572864 would be displayed as "1.5 MB" because 1572864/1024/1024 = 1.5. The conversion to text should be controlled by settings/properties in the DataGridDataSizeColumn class. Sorting must be performed using the original integer value not the displayed text.
DataGridCustomColumn This should operate similar to the preexisting DataGridTemplateColumn except without the Windows.UI.Xaml.DataTemplate. It should invoke a delegate/callback or event to generate and/or update the displayed GUI element subtree.
DataGridTextColumn Already exists but please consider adding properties or events that allow apps to override the object-to-text conversion and the comparison function for sorting. I explain this in more detail later in my message.

DataGridCustomColumn would be like this:

public class DataGridCustomColumn : DataGridColumn
{
    public event EventHandler<DataGridDisplayingCellEventArgs> DisplayingCell;
}

public class DataGridDisplayingCellEventArgs : EventArgs
{
    public DataGridColumn Column { get; }
    public object CellValue { get; }
    public Windows.UI.Xaml.UIElement CellUIElement { get; set; } // settable
}

When the event DataGridCustomColumn.DisplayingCell is triggered, the event handler should generate or update its own UIElement subtree to display the DataGridDisplayingCellEventArgs.CellValue, and set the property DataGridDisplayingCellEventArgs.CellUIElement to that UIElement subtree, and then DataGrid will display it.

The next time DataGrid triggers this event, DataGrid should set the property DataGridDisplayingCellEventArgs.CellUIElement to the UIElement instance that was previously generated by the event handler, in order to allow the event handler to reuse/recycle and update the same UIElement subtree (potentially with a different value in DataGridDisplayingCellEventArgs.CellValue). The event handler is allowed to either recycle the same UIElement subtree OR set the property DataGridDisplayingCellEventArgs.CellUIElement to a newly created UIElement subtree.

Also consider the possibility of making the new DisplayingCell event directly in the base class DataGridColumn, instead of making the subclass DataGridCustomColumn. Thus the event DataGridColumn.DisplayingCell could allow customization or overriding of the generated UIElement for every subclass of DataGridColumn.

In the preexisting DataGridTextColumn, currently the cell value/object is converted to text for display by invoking System.Object.ToString. Please consider making a delegate/callback or event that allows apps to override this value-to-text conversion. Please also consider a property that allows apps to specify a System.Collections.IComparer instance to override the sorting behavior.

public class DataGridTextColumn : DataGridColumn
{
    public System.Collections.IComparer Comparer { get; set; }
    public DataGridCellValueToToStringConverter CellValueToToStringConverter { get; set; }
}

public delegate string DataGridCellValueToToStringConverter(object sourceObject);

Alternatively, instead of making the Comparer property in DataGridTextColumn, consider the possibility of making the Comparer property directly in the base class DataGridColumn, in order to allow apps to control the sorting behavior for all subclasses of DataGridColumn.

Likewise the CellValueToToStringConverter property could also be made in the base class DataGridColumn because it would be useful to have the ability to convert any cell value to text regardless of which subclass of DataGridColumn is used. For example, when copying a row to the clipboard, each cell value could be converted to text. (Both text and non-text formats may be simultaneously placed in the clipboard -- apps commonly do this in order to increase compatibility with other apps.)

Re sorting when a DataGridIconColumn or DataGridImageColumn is selected: Obviously DataGrid cannot sort icons or images, therefore it could use any one of these solutions:

Access to selected rows/items

Please consider improving the functionality for getting and setting the selected rows/items, because the current functionality is insufficient. Currently these properties exist:

public int SelectedIndex { get; set; }
public object SelectedItem { get; set; }
public System.Collections.IList SelectedItems { get; }

I found that sometimes I needed access to the DataGridRow instances of the selected rows, thus I hope that the following properties can be added to DataGrid:

public DataGridRow SelectedRow { get; set; }
public IList<DataGridRow> SelectedRows { get; }

Alternatively, if the above is too difficult to implement, the following read-only variation is less powerful but still helpful:

public DataGridRow SelectedRow { get; }
public IReadOnlyCollection<DataGridRow> SelectedRows { get; }

If DataGridRow instances may be recycled, then the documentation for the above properties should warn that the returned info is only temporarily valid, thus it should be read/used immediately and not retained for a longer length of time.

Also, the preexisting SelectedIndex property gives access to one selected index, but what about getting access to all of the selected items? Therefore I suggest making the following SelectedIndexes property:

public IList<int> SelectedIndexes { get; } // Suggestion.
public int SelectedIndex { get; set; } // Already exists.

Personally I find the name "SelectedIndex" confusing because DataGrid is often used in conjunction with a database and the term "index" has a completely different meaning in a database, therefore I suggest renaming the properties as follows, but I expect that my naming suggestion will be rejected:

public IList<int> SelectedOrdinals { get; }
public int SelectedOrdinal { get; set; }

I also wish for the ability to scroll the specified DataGridRow and/or DataGridColumn into view. Currently this method exists:

public void ScrollIntoView(object item, DataGridColumn column);

I suggest replacing the preexisting ScrollIntoView method with these 2 methods:

public void ScrollIntoView(DataGridRow row, DataGridColumn column);
public void ScrollItemIntoView(object item, DataGridColumn column);
verelpode commented 5 years ago

Get and set sort-order in one hit

When apps are opened and closed, they need the ability to save and restore the end-user's configuration of the DataGrid, including the sort order and other settings. Sort order meaning the list of columns that were selected by the user. Note this is a list, not a single column. More than one column may be selected simultaneously, meaning the primary column for sorting, and the secondary column for sorting, and the tertiary column for sorting, etc.

Therefore the following property could be made in DataGrid, but actually this is only the first idea and it isn't ideal:

public IReadOnlyList<DataGridColumn> SortOrder { get; set; }

The above is non-ideal because it doesn't support the saving and restoring of the DataGridColumn.SortDirection of each column in one hit. I realize that apps could do it in multiple steps:

  1. Set the proposed SortOrder property to the list of selected columns.
  2. Set the SortDirection property of each of the selected columns (repeat this step for each column).

That's still problematic because it's multiple hits, meaning it causes multiple time-consuming resorts of the DataGrid. End-users could notice and suffer a significant delay in a DataGrid that contains a large number of rows, when the DataGrid is resorted multiple times unnecessarily. To eliminate this problem, I suggest the following solution that allows apps to restore the complete sort-order in one hit and cause no more than a single resort.

public class DataGrid
{
    public IReadOnlyList<DataGridColumnAndDirection> SortOrder { get; set; }
    ...
}

public struct DataGridColumnAndDirection
{
    public readonly DataGridColumn Column;
    public readonly DataGridSortDirection SortDirection;
    public DataGridColumnAndDirection(DataGridColumn, DataGridSortDirection) { ... }
}

Note I deliberately wrote IReadOnlyList<DataGridColumnAndDirection> not IList<DataGridColumnAndDirection> above because apps shouldn't be able to modify the list returned by the SortOrder property. Instead of modifying the list, apps should set the SortOrder property to a list that DataGrid will copy and use to completely replace the entire sort order list. Thus it would operate in one hit and avoid multiple expensive resorts.

When DataGrid.SortOrder is set to a new list, DataGrid would also set the corresponding DataGridColumn.SortDirection property in each column in the new SortOrder list, but without causing multiple resorts. Thus DataGrid.SortOrder[i].SortDirection is equivalent to DataGridColumn.SortDirection.

Get and set displayed column order in one hit

When apps are opened and closed, they need the ability to save and restore the end-user's ordering of the columns, preferably in one hit. I know that the preexisting property DataGridColumn.DisplayIndex is settable, therefore theoretically apps could restore the end-user's configuration by iterating through all columns in DataGrid.Columns and set the DisplayIndex of each, but this might cause bugs. For example, DisplayIndex might fail or behave in an unexpected manner when an app needs to temporarily set the DisplayIndex of one column to the same DisplayIndex of another column. Also, if it isn't performed in one hit, then it could trigger multiple expensive redraws and/or recalculations.

Therefore I suggest making a ColumnDisplayOrder property in DataGrid:

public IReadOnlyList<DataGridColumn> ColumnDisplayOrder { get; set; }

The same as I mentioned previously for SortOrder, ColumnDisplayOrder is deliberately IReadOnlyList<DataGridColumn> not IList<DataGridColumn> because it should operate in one hit. When DataGrid.ColumnDisplayOrder is set to a new list, DataGrid would update the DataGridColumn.DisplayIndex of each column to match.

Allow end-users to hide/show columns

Consistent with the preexisting properties DataGridColumn.CanUserReorder etc, I suggest making a CanUserChangeVisibility property in DataGridColumn. When DataGridColumn.CanUserChangeVisibility is true, the end-user would be able to cause changes to the property DataGridColumn.Visibility.

Support GUI elements generated dynamically at runtime

Allow the row-details GUI to be generated without requiring the use of DataGrid.RowDetailsTemplate (Windows.UI.Xaml.DataTemplate). In order to achieve this, some thought needs to be put into the API, but here's my first idea for how to do it: Maybe do it via the preexisting event DataGrid.LoadingRow by changing the property DataGridRowDetailsEventArgs.DetailsElement to be settable so that the event handler can generate (or update) the UIElement by itself and give it to DataGrid by setting the DetailsElement property.

The reason why mandatory use of Windows.UI.Xaml.DataTemplate is a problem: Although templates are a good feature, the template concept expects a precreated unchanging XAML snippet/document that was written by the developer in advance. Thus templates are a problem when the app needs to dynamically generate the GUI at runtime. Thus I wish for the aforementioned alternatives to DataTemplate.

Drag-and-drop of rows, inwards and outwards

I suggest making the ability to optionally enable outgoing drag-and-drop of rows. DataGrid would implement the drag but not the drop. When the drop occurs, DataGrid would trigger an event and the app responds to the event in order to perform the desired action when the row is dropped outside of the DataGrid.

Also the ability to optionally enable incoming drag-and-drop of rows or items/objects. DataGrid would accept incoming drag-and-drop but does not implement the drop. DataGrid would trigger an event when the row/item/object is dropped, and the app responds to the event in order to to perform the desired action when the row is dropped inside the DataGrid.

Individual cell backgrounds

We have a feature request from a customer who wants individual cells to be hilited (by changing the cell background color/brush) at certain times (such as when our app detects changes or important values or dangerous values exceeding safety limits etc).

Thus I could propose a DataGridCell.Background property (of type Brush), but I think this way of doing it is probably defective because DataGrid recycles DataGridCell instances, doesn't it? So I guess that hiliting individual cells by setting a DataGridCell.Background property would be an unreliable solution.

A better way might be via the event DataGridColumn.DisplayingCell that I proposed in my previous message. The event handler could set a CellBackgroundBrush property in DataGridDisplayingCellEventArgs.

Dumb-down DataGrid's retrieval of data (cell values)

I know "dumb" sounds very bad, but in reality I would love it if DataGrid was made dumb in the area of data-retrieval (retrieval of the cell values to be displayed by DataGrid).

Currently DataGrid attempts to perform data retrieval in a convenient automatic manner via its property DataGrid.ItemsSource plus data-binding techniques (the property DataGridBoundColumn.Binding), and interfaces such as System.ComponentModel.INotifyPropertyChanged.

Yes data-binding is a convenient feature, but actually I'd much prefer to have DataGrid do less in that department! Several Microsoft components actually cause large difficulties for me via their behavior of trying to be smart but actually ending up being too smart. Overall I'd actually experience fewer difficulties and less work if these components would cease trying to be so smart/automatic/convenient. When designing an automatic behavior, I find it worthwhile to keep in mind that automatic sounds great but has the potential to backfire.

"Just simply let me do it by myself." Sometimes the best solution is to just simply allow apps to perform the task by themselves, instead of trying-and-failing to do it "automatically" inside a component such as DataGrid. I wish that DataGrid would allow me to completely perform the data retrieval by myself, instead of trying to automatically retrieve the data via the properties DataGridBoundColumn.Binding and DataGrid.ItemsSource.

Ideally I'd like to eliminate the requirement to use the property DataGrid.ItemsSource to supply the items. @dotMorten mentioned a million rows. Currently DataGrid makes it mandatory for apps to set DataGrid.ItemsSource, but it is impractical to create a list object that contains a million items. Thus I wish that DataGrid would stop being smart in the data-retrieval department and instead let me completely perform the data retrieval by myself, without using DataGridBoundColumn.Binding and DataGrid.ItemsSource.

@anawishnoff wrote:

Performance is definitely one of the main motivations for this project and one of the main improvements we want to implement, through a new data virtualization story and the use of modern controls such as ItemsRepeater.

I see you said the new data virtualization story will improve performance, and that's good news, but will it also eliminate the requirement to use the property DataGridBoundColumn.Binding in order to supply the cell values that DataGrid displays?

If the entire data retrieval job is outsourced to the app that uses DataGrid, then the app has complete flexibility to perform the data retrieval in any manner that it needs. This would enable many different data-retrieval scenarios, including the million rows that @dotMorten mentioned. Dumb it down, please :smile:

A few unnecessary features in WPF DataGrid?

The WPF version of DataGrid has a few features that seem unnecessary or impractical, and these features could be skipped in WinUI DataGrid, but I expect that some people probably have a different opinion about these features.

How many people would raise an objection if WinUI DataGrid abandoned the feature where end-users are able to edit cell values inline/directly inside the DataGrid? In our case, in every place where we use DataGrid, we always set DataGrid.IsReadOnly to true to disable the inline/direct editing feature. We allow users to edit the selected row in a separate pane or panel, or in RowDetails (DataGrid.RowDetailsTemplate), but not directly inside the DataGrid itself.

It seems like WinUI DataGrid has already moved in the direction of dropping support for inline/direct editing because WPF DataGrid had CanUserAddRows and CanUserDeleteRows but these properties don't exist anymore in WinUI DataGrid. Why not go all the way to dropping the inline/direct editing feature entirely? How many people have objections to this idea?

Individual cell selection: WPF DataGrid has a SelectionUnit property that you can set to Cell, FullRow, or CellOrRowHeader. In our case, we always set it to FullRow and never found a need to set it to Cell. However I see one person here has already requested single cell selection mode. My question is whether cell selection mode is a common or rare request.

On the other hand, individual cell selection might be useful when the user copies rows/cells to the clipboard. It would allow users to copy an individual cell (or several contiguous cells) to the clipboard instead of copying the entire row. However I'm unsure whether this feature is truly valuable or not.

Dubious Feature in WPF Comments
DataGrid.IsReadOnly Maybe no real need to ever set IsReadOnly to false?
DataGrid.CanUserAddRows Doesn't exist in WinUI DataGrid. Already abandoned, or maybe not yet implemented (I don't know the plan).
DataGrid.CanUserDeleteRows Doesn't exist in WinUI DataGrid. Already abandoned, or maybe not yet implemented (I don't know the plan).
DataGrid.SelectionUnit Doesn't exist in WinUI DataGrid.
thomasclaudiushuber commented 5 years ago

Wow, incredible discussion here. ❤️

I also agree to the WPF DataGrid API. The WPF DataGrid is really the DataGrid I want for WinUI 3.0.

But even the WPF DataGrid lacks some features. In the past, most of my customers used a more powerful 3rd party DataGrid to get these features:

But anyway, what ever you do, I think building a DataGrid is a powerful statement and commitment to WinUI 3.0. For LOB applications you can't take a UI framework serious that doesn't contain a built-in DataGrid. And it's great to see this investment made for WinUI!

verelpode commented 5 years ago

@thomasclaudiushuber

For LOB applications you can't take a UI framework serious that doesn't contain a built-in DataGrid. And it's great to see this investment made for WinUI!

Agreed! In our case, DataGrid is a critically essential component that we use in multiple places and cannot live without.

Powerful display of hierarchical data. Some 3rd party DataGrids really work like a powerful TreeView with nested DataGrids.

I'm torn on that topic because -- like you -- I would find a hierarchical DataGrid useful in some situations, but my concern is that if DataGrid does implement hierarchical functionality, then it could become excessively complex and difficult, and the release of DataGrid would most likely be delayed substantially. New features would be difficult to add because of the complexity of making new features compatible with both hierarchical and non-hierarchical functionality.

To eliminate the aforementioned complexity/delays problem, I suggest this solution: Make a separate class named HierarchicalDataGrid that internally uses/wraps an instance of DataGrid. Alternatively HierarchicalDataGrid could publicly inherit DataGrid but I suspect this inheritance is impractical, therefore I prefer to suggest that HierarchicalDataGrid inherit Control and internally have a private field of type DataGrid. Thus the hierarchical functionality would be implemented in the HierarchicalDataGrid layer that directs an internal non-hierarchical DataGrid instance.

The key advantage of the above solution is that would deliver the desired hierarchical features without bogging down DataGrid, without making DataGrid so complex that it becomes unmanageable and slow to develop.

Support for different data types. Like for example a DateTime column.

I agree. Check out the DataGridDateTimeColumn and DataGridTimeSpanColumn that I proposed in a previous message.

verelpode commented 5 years ago

@Pinox

Easy filter the whole page

@thomasclaudiushuber

Filters in the Column Headers; A complete filter row at the top of the DataGrid;

Filters would be great for helping end-users quickly find a row or rows, instead of the current situation of being forced to manually look at a large number of rows to find what they're looking for.

But what about the problem of matching the user's filter text with non-text columns? Meaning columns other than DataGridTextColumn, such as filtering with DataGridTemplateColumn etc? I suggest solving this with something approximately like the following solution that gives DataGridColumn (and subclasses) the ability to convert a cell value to keywords for use with searching/filtering/matching.

public delegate void DataGridCellValueToKeywordsConverter(object cellValue, ICollection<string> outputKeywords);

public class DataGridColumn
{
    ...
    public DataGridCellValueToKeywordsConverter CellValueToKeywordsConverter { get; set; }

    /// <param name="cellValue">The input/source value of the cell, to be converted to keywords.</param>
    /// <param name="outputKeywords">A collection that the method will add the keywords to.  The method invokes ICollection.Add for each keyword.</param>
    public virtual void ConvertCellValueToKeywords(object cellValue, ICollection<string> outputKeywords)
    {
        // Subclasses can override this method.  The default behavior is to invoke the delegate to do the job.
        DataGridCellValueToKeywordsConverter d = this.CellValueToKeywordsConverter;
        if (!(d is null)) d(cellValue, outputKeywords);
    }
}

Here is an example of how to use the ConvertCellValueToKeywords method:

void TestKeywords(DataGridColumn column)
{
    var keywords = new System.Collections.Generic.HashSet<string>();
    foreach (object cellValue in someCellValueList)
    {
        keywords.Clear();
        column.ConvertCellValueToKeywords(cellValue, keywords);
        CheckIfFilterTextMatchesAnyKeyword(keywords);
    }
}

Alternatively, the cell value could be converted to a single string instead of a collection of keywords, but the reason why I suggested a keywords collection is that keywords make it possible to use searching algorithms that run at high speed even when the quantity of rows is very large.

khoshroomahdi commented 5 years ago

Easy copy past from excel Now there no way to use ctrl+v to copy Excel cells content to datagrid. Now it copy all cells content to one cell in data grid.

alexyak commented 5 years ago

Please provide a proper multiple selected items support, by making SelectedItems as a dependency property to allow using data binding when managing selected rows.

michael-hawker commented 5 years ago

@verelpode I can see individual cell selection being useful for any spreadsheet type application, no? I think it matters more in edit scenarios vs. view scenarios. When viewing data in a datagrid without edit, I agree I wouldn't see a use for individual cell selection and always have full row selection.

@anawishnoff I think @Laz3rPanth3r would agree and the couple of issues here and here from the toolkit that being able to ingest data easily and simply into the DataGrid is an important feature. You should be able to boot-strap the grid by binding to a collection of objects or expando objects in a list. If it can intelligently select columns for numbers and strings and basic data types, that'd be great. The developer can always do more work after to customize individual columns beyond that.

verelpode commented 5 years ago

I can see individual cell selection being useful for any spreadsheet type application, no?

In a spreadsheet, the column headers are named with ascending letters of the alphabet, A, B, C, D, … and the type of every column is the same, as if every column uses DataGridTextColumn and no other column type is needed, and column names aren't really needed either because they're generated automatically from the alphabet. Another difference between DataGrid and a spreadsheet is that a spreadsheet doesn't sort the rows when you click any of the column headers.

My point is, only a superficial similarity (mostly a visual similarity) exists between DataGrid and a spreadsheet. DataGrid doesn't really operate like a spreadsheet. The cell data retrieval technique of DataGrid is also poorly suited to a spreadsheet.

I love DataGrid but it would function poorly if I tried to use it to implement a spreadsheet. I don't think DataGrid is the right choice for anyone who wants to implement a spreadsheet.

The existing design of DataGrid aligns far better with an SQL database than a spreadsheet, and SQL database developers would yell loudly if someone tried to claim that a database is "just a spreadsheet".

anawishnoff commented 5 years ago

@verelpode Your contributions are so detailed and thought-out, thank you so much for all of that! I want to talk about the idea of binding a data source/the ItemsSource property of DataGrid, as you mentioned and @michael-hawker did as well.

Currently DataGrid makes it mandatory for apps to set DataGrid.ItemsSource, but it is impractical to create a list object that contains a million items. Thus I wish that DataGrid would stop being smart in the data-retrieval department and instead let me completely perform the data retrieval by myself, without using DataGridBoundColumn.Binding and DataGrid.ItemsSource.

This is interesting, and I'd like to look more into it as we are really interested in performance. What sort of data situation/scenario are you looking for, specifically? Would you want to connect the DataGrid straight to an SQL query result, or a database, or something along those lines?

@khoshroomahdi By copy and paste, do you mean you'd want to copy excel cells into a DataGrid in a running app, and populate in that way? That's an interesting use case, I'd like to hear more.

@alexyak, could you expand a bit further? The SelectedItems property currently allows you to get all selected items in a DataGrid (through extended selection mode though, not precisely multiple selection mode). I see from a few other comments here that selection within a DataGrid definitely needs work, but I want to understand your request better.

khoshroomahdi commented 5 years ago

@anawishnoff yes exactly. I have some data in excell cells and want to copy them in running app.

RBrid commented 5 years ago

For non-data-bound scenarios, we should look at how the WinForms DataGridView control, which I wrote many years ago, supported a virtual mode: https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.datagridview.virtualmode

robloo commented 5 years ago

Currently DataGrid makes it mandatory for apps to set DataGrid.ItemsSource, but it is impractical to create a list object that contains a million items. Thus I wish that DataGrid would stop being smart in the data-retrieval department and instead let me completely perform the data retrieval by myself, without using DataGridBoundColumn.Binding and DataGrid.ItemsSource.

I agree that would be nice as well. I'm thinking something like ListBox where you can either add Items manually or set the ItemsSource. That said, in the past I just generate a new DataTable representing a partial view of the full database to implement paging (which is a good use case for this). A view of that DataTable can then be set to ItemsSource. So while I definitely think this is nice to have it doesn't seem mandatory for high performance.

Concerning all the comments turning the control into more-or-less a subset of Excel(r), I think out of the box the DataGrid should support cell selection and per-cell editing. However, things like copy/paste between external applications should be handled by the developer.

@alexyak Concerning your request to making SelectedItems a real, bindable DependencyProperty this would be great to restore state as well (most of my feature requests so far are to restore view state). I think this is a framework-wide issue though as it's not supported in any WinUI/UWP controls I am aware of. This should probably be a general feature request. See discussion here

verelpode commented 5 years ago

@anawishnoff wrote:

Your contributions are so detailed and thought-out, thank you so much for all of that!

Thanks, I'm glad to hear that my contributions are useful in making DataGrid even better :)

What sort of data situation/scenario are you looking for, specifically? Would you want to connect the DataGrid straight to an SQL query result, or a database, or something along those lines?

That's still too smart. This smart behavior prevents different apps from performing the data retrieval in different manners. Different apps have vastly different circumstances, thus the "best" data retrieval system is different for different apps -- no single "best" exists. For example, some apps never display more than a couple hundred rows, whereas some other apps may work with a million rows like @dotMorten mentioned, therefore one shoe size does not fit all.

I suggest really dumbing it down to this level:

  1. DataGrid decides that it needs to display (or otherwise use) the value that exists in column 5 of row 9001 in the external data storage system.
  2. DataGrid notifies the app that it needs the value for column 5 of row 9001.
  3. The app retrieves the value for column 5 of row 9001. This may involve an async SQL query, or an async C# Task, or any other data system. Ideally DataGrid should allow this step to be async.
  4. The app notifies DataGrid that it finished retrieving the value for column 5 of row 9001. The app gives this value to DataGrid.
  5. DataGrid uses the value in whatever manner it needed to, such as displaying the value as mentioned in step 1.

@RBrid wrote:

For non-data-bound scenarios, we should look at how the WinForms DataGridView control, which I wrote many years ago, supported a virtual mode:

Yes yes yes! I've never used WinForms DataGridView, but I just read the documentation now and I believe you've hit the nail on the head. The webpage you linked to says: "Virtual mode is designed for use with very large stores of data."

I see that the WinForms DataGridViewCellValueEventArgs contains these properties:

public int RowIndex { get; }      // DataGrid sets RowIndex.
public int ColumnIndex { get; }   // DataGrid sets ColumnIndex.
public object Value { get; set; } // The app sets Value.

That's excellent, except that ideally it should be updated to support the modern C# async and await keywords, or the UWP equivalent (IAsyncOperation<TResult>), or rather any kind of time delay between DataGrid requesting the cell value and the app delivering the cell value to DataGrid. Thus to update it to support async, do this:

  1. Keep the event CellValueNeeded.
  2. Remove the property DataGridViewCellValueEventArgs.Value.
  3. Create a method in DataGrid named something like SupplyCellValue that the app will invoke, instead of being required to immediately/synchronously set the property DataGridViewCellValueEventArgs.Value.

The SupplyCellValue method might be defined like this:

class DataGrid
{
    public void SupplyCellValue(int rowIndex, int columnIndex, object value);
    // Alternatively:
    public void SupplyCellValue(int rowIndex, DataGridColumn column, object value);
}

Thus at runtime the procedure is:

  1. DataGrid decides that it needs to display (or otherwise use) the value that exists in column 5 of row 9001 in the external data storage system.
  2. DataGrid triggers the event CellValueNeeded and sets DataGridViewCellValueEventArgs.RowIndex to 9001 and DataGridViewCellValueEventArgs.ColumnIndex to 5.
  3. The event handler (the app) starts running an async task that will retrieve the value for column 5 of row 9001.
  4. When the async task finishes running, meaning when the app has retrieved the value, the app invokes the method DataGrid.SupplyCellValue.

This dumbed-down technique is more powerful and flexible than the smart automated technique of DataGridBoundColumn.Binding and DataGrid.ItemsSource.

alexyak commented 5 years ago

@alexyak, could you expand a bit further? The SelectedItems property currently allows you to get all selected items in a DataGrid (through extended selection mode though, not precisely multiple selection mode). I see from a few other comments here that selection within a DataGrid definitely needs work, but I want to understand your request better.

We need a proper two way databinding for viewmodels to manage multiple selections

RBrid commented 5 years ago

@verelpode, we had modeled the WinForms DataGridView model after the even older Win32 ComCtl32 controls. In particular, I'm thinking about how the list-view control used the LVN_GETDISPINFO message in virtual mode (see https://docs.microsoft.com/en-us/windows/win32/controls/list-view-controls-overview#handling-virtual-list-view-control-notification-codes and https://docs.microsoft.com/en-us/windows/win32/controls/lvn-getdispinfo). Old stuff from the '90.

Anyways, I believe the way the asynchronous data retrieval aspect should be handled is through 'deferred events'. WinUI controls already use deferred events twice:

runtimeclass RefreshRequestedEventArgs
{
    Windows.Foundation.Deferral GetDeferral();
}

runtimeclass TeachingTipClosingEventArgs
{
    TeachingTipCloseReason Reason{ get; };
    Boolean Cancel;
    Windows.Foundation.Deferral GetDeferral();
}

It's the pattern the new DataGrid's CellValueNeeded event would want to adopt. It allows the event handler to supply data asynchronously and tell the control when it's done doing so. See https://docs.microsoft.com/en-us/uwp/api/windows.foundation.deferral.

verelpode commented 5 years ago

@RBrid Good point about GetDeferral() being the new standard pattern. In this particular case of CellValueNeeded, it seems much more difficult to use Deferral than in other cases/events. Correct me if I'm wrong, but I think the problem with using GetDeferral() in this particular case is that GetDeferral() creates a new object every time it is invoked, and this would lead to an excessively huge amount of object creation and clean-up being repeated for every cell of every row of a potentially large number of rows. I haven't seen the source code of various GetDeferral() implementations therefore I could be mistaken about this.

In other words, unless Deferral supports recycling or otherwise has a way of making GetDeferral() much more efficient, then it's still too smart. My dumbed-down proposal with the SupplyCellValue method avoids incurring the overhead of creating, completing, and disposing a new Deferral instance for every cell of every applicable row.

  1. GetDeferral()
  2. Deferral.Complete
  3. Deferral.Dispose
  4. Repeat the above steps a large number of times.

The task of retrieving a cell value is not the only data management task that may be outsourced to the app. Sorting might also be outsourced. Therefore it might be worthwhile to consider thinking of an interface instead of a single event CellValueNeeded. An app would give DataGrid a data management module in the form of an object that implements a certain interface. DataGrid would invoke this interface in order to retrieve cell values, but also potentially other tasks such as sorting.

To support the million rows that @dotMorten mentioned, CellValueNeeded alone wouldn't solve the other problem that occurs when the user clicks a column header and the DataGrid tries to sort a million rows. Thus cell retrieval AND sorting could be outsourced to the app via the aforementioned module/interface.

If the app doesn't supply any data management module/object to DataGrid, then ideally DataGrid would use a default data management module. Thus all of the existing data-binding code in DataGrid would be moved out of DataGrid and into a separate new class -- the class that implements the default data management module by working with DataGridBoundColumn.Binding etc.

i.e. when sorting is also outsourced to the app or its data management module, then this opens the door to various solutions that support a million rows, such as writing a data management module that instructs the SQL server to perform the sorting, instead of trying-and-failing to do the sorting of a million rows inside DataGrid in less time than 10 or 20 hours after the user clicks the column header to begin the sorting.

RBrid commented 5 years ago

@verelpode, yes that's a valid concern. I would expect the DataGrid to own a pool of recyclable Windows.Foundation.Deferral objects. We would need to confirm the feasibility and perf for sure.

bent-rasmussen commented 5 years ago

Having taken a dependency on the Windows Community Toolkit DataGrid which has Row Details as a feature (albeit with a serious performance bug but with a workaround), we would really like this new datagrid to have that as a feature as well - with the same option to have multiple row details concurrently. Using it for a server to client streaming data scenario.

verelpode commented 5 years ago

Re a million rows versus a paging GUI, @robloo wrote:

I agree that [supporting a million rows] would be nice as well. .... That said, in the past I just generate a new DataTable representing a partial view of the full database to implement paging (which is a good use case for this). A view of that DataTable can then be set to ItemsSource. So while I definitely think this is nice to have it doesn't seem mandatory for high performance.

Paging is a useful technique and worthwhile mentioning, but it has substantial disadvantages: It makes DataGrid's sorting feature practically useless. Likewise for a filtering feature in the next version of DataGrid. Paging makes sorting and filtering useless or at least much less useful.

For example, imagine that 2 or 3 columns are date columns, and the user wants to view the rows that have the most recent (or the oldest) date in the second date column. Thus the user clicks the second date column header to sort the DataGrid by that column, and also clicks to change sort-direction from descending to ascending or vice-versa. This works great if no paging is in-use, or if the total quantity of rows is small enough to not exceed a single page, but it breaks if multiple pages exist.

The user needs to find the most recent (or oldest) date across all rows but a paged DataGrid GUI only shows the most recent (or oldest) date in the current page, not across all rows, thus paging makes sorting (and filtering) practically useless.

This raises the question of which rows land in which page. The answer is that each page typically contains a practically-random subset of the rows, when the pages/rows are obtained via an SQL SELECT query that doesn't use ORDER BY. (I mean random from the user's point-of-view, not truly random.)

Pseudo-random is unhelpful for end-users. To eliminate this problematic randomness, we could think about using SQL ORDER BY (along with the ASC or DESC keyword to control sort-direction), and then yes the pages are no longer random, but it's still broken because this usage of ORDER BY always sorts by the same column and same sort-direction, meaning the sort order is frequently different than the sort order chosen by the end-user clicking on a column header in DataGrid.

To fix it, you would need to use a different SQL query each time the user clicks on a different column header. The SQL ORDER BY ... ASC/DESC would need to be kept the same as whatever sort order is chosen by the end-user of DataGrid. DataGrid does not support this currently.

A suggested solution is in my previous message: I've suggested that DataGrid should allow sorting to be outsourced to the app (or to a "data management module"). This idea would make it possible for the app (or "data management module") to change the SQL ORDER BY ... ASC/DESC whenever the end-user changes the sort-order of DataGrid by clicking on column headers etc.

It might also be worthwhile to give the preexisting event DataGrid.Sorting a settable property in the event args that allows apps (the event handler) to cancel the sorting and take over. Ideally the event args would also specify whether the sort order change was requested programmatically versus requested by the end-user clicking on column headers etc. In this case, it might also help to rename the event DataGrid.Sorting to something less ambiguous because currently the intention and purpose of the Sorting event is unclear. See also the proposed event SortOrderChanged in my other message.

christian-clausen commented 5 years ago

Having taken a dependency on the Windows Community Toolkit DataGrid which has Row Details as a feature (albeit with a serious performance bug but with a workaround), we would really like this new datagrid to have that as a feature as well - with the same option to have multiple row details concurrently. Using it for a server to client streaming data scenario.

Link to the Row Details performance issue: https://github.com/windows-toolkit/WindowsCommunityToolkit/issues/2842 Repro: https://github.com/observito/DataGridRowDetailsPerfTest

FrancoisM commented 4 years ago

A good starting point is looking at your partner Telerik with their RadDataGrid (UWP Open Source). With one of my clients, I used it and it actually works well. It is hyper fast and versatile. The only thing that is difficult is their code, there is no way to modify anything from their engine without a good comprehension of the architecture.

I would expect the new DataGrid to be as performant as Telerik.

The syncfusion grid features are great but they aren't mvvm friendly. So you could do better.

anawishnoff commented 4 years ago

Hey again all! Let's keep this conversation going. What are your thoughts on the DataGrid documentation that currently exists?

Here's a link to the main documentation page that links to all of the other relevant pages.

If we create a new DataGrid, we want to make sure the documentation that accompanies it will be top-notch, easy to understand, and addresses all of the issues and scenarios that are important to our developers.

What are some topics you wish we had? What are some topics that could be clarified?

mdtauk commented 4 years ago

Hey again all! Let's keep this conversation going. What are your thoughts on the DataGrid documentation that currently exists?

Here's a link to the main documentation page that links to all of the other relevant pages.

If we create a new DataGrid, we want to make sure the documentation that accompanies it will be top-notch, easy to understand, and addresses all of the issues and scenarios that are important to our developers.

What are some topics you wish we had? What are some topics that could be clarified?

Images showing typical DataGrid setups, along with the xaml and code to make them, would be useful.

anawishnoff commented 4 years ago

Images showing typical DataGrid setups, along with the xaml and code to make them, would be useful.

@mdtauk Are there any specific DataGrid setups that you find to be "typical", or use cases in which you consistently find DataGrid being the best choice to use?

mdtauk commented 4 years ago

Images showing typical DataGrid setups, along with the xaml and code to make them, would be useful.

@mdtauk Are there any specific DataGrid setups that you find to be "typical", or use cases in which you consistently find DataGrid being the best choice to use?

I think for the WinUI 3.0 timeframe, showing common WPF, Win32 data grid/icon view scenarios. As well as what Microsoft considers Fluent/Modern DataGrid UI designs.

That is if the idea behind the control, is to encourage moving from old UIs to WinUI 3

michael-hawker commented 4 years ago

@anawishnoff I think some of the questions we had from the toolkit in terms of things people were looking for documentation on where more of these scenarios as well:

lukeblevins commented 4 years ago

I noticed that the existing Toolkit DataGrid requires a IEnumerable for it's ItemsSource property. While this seems like a logical decision, it makes setting the object returned by Windows.Storage.BulkAccess.FileInformationFactory.GetVirtualizedItemsVector() as this property impossible. (Unless there is a way to cast the object returned) Furthermore, other controls like ListView and GridView support setting their ItemsSource property to a value of the object type. I'm not certain, but supporting this would likely allow for a more responsive user interface during storage operations.

mdtauk commented 4 years ago

@mdtauk Are there any specific DataGrid setups that you find to be "typical", or use cases in which you consistently find DataGrid being the best choice to use?

I think for the WinUI 3.0 timeframe, showing common WPF, Win32 data grid/icon view scenarios. As well as what Microsoft considers Fluent/Modern DataGrid UI designs.

That is if the idea behind the control, is to encourage moving from old UIs to WinUI 3

Win32 example (File Explorer) image

WPF example image

Fabric Web example image

UWP example image

anawishnoff commented 4 years ago

@mdtauk Thanks for those screenshots! I definitely think it's important to highlight the key elements that have worked in previous versions of the control and document how they can be achieved with the new control.

@michael-hawker Awesome. I'm already seeing a few topics in there that have been brought up multiple times on this thread, so those are definitely a good place to start.

@duke7553 I'm not 100% sure about a solution to that, or if supporting an object type would be wise. Maybe @RBrid can chime in?

RBrid commented 4 years ago

@anawishnoff & @duke7553, I would build the new DataGrid control on top of the new WinUI ItemsRepeater control. And that control exposes its ItemsSource as an Object: Object ItemsSource { get; set; };

kevin-jing commented 4 years ago

Hope it support CellDecorationStyleSelector as in Telerik.

verelpode commented 4 years ago

@anawishnoff

we are interested in graduating it to a native WinUI control

hmmmm when you say "graduating", would that include downgrading it to C++? Currently WinUI's DataGrid is written in C#. I hope that "graduate" won't mean "downgrade". Importantly, WinUI needs to reach a point where the WinUI team can say that WinUI is better than WPF in every way that matters, but this goal is terribly overdue. This goal will become even more overdue if time/resources are wasted in unnecessary downgrades of code such as DataGrid from C# to C++.

Although there originally existed a reason for writing WinRT/UWP/WinUI in C++, unfortunately that reason didn't reach fruition, and Google/Android took most of the smartphone marketshare, therefore the original reason for using C++ isn't applicable anymore (easily said in hindsight, but not so easy to say earlier). If WinUI was written in C# from the beginning, then the better-than-WPF goal would have been achieved 3 years ago, but now it's 8 years and still not achieved, and nobody is able to accurately say when the goal will be reached. Hopefully the better-than-WPF goal and the WinUI DataGrid "graduation" goals won't be delayed by an unnecessary conversion to an older and less productive programming language.

I'm biased in favor of C++ because I started programming in C++ before C# even existed, and people prefer to stick with what they originally learned, and fondly remember "the good old days". Despite my bias in favor of C++, I stopped writing C++, and I think DataGrid shouldn't be downgraded to C++ and delayed. Leave it as C# and focus on more important things such as making the various improvements suggested by people in this issue, and achieving the better-than-WPF goal before 1 decade is reached.

I love many aspects of WinUI, and I appreciate the many clever improvements in it, and I write app code for WinUI, but do you want to know the honest truth? The truth is, sadly I've not yet released any WinUI app to users, ever. The software released to the users is written with WPF, and the users don't care because the software works well and includes GUI modernizations. Although I've written a whole bunch of app code for WinUI, it's all preparation, planning, testing, waiting, not actually in-use by the users. Hopefully next year the first WinUI component will be released to the users, but I will appreciate this switch-over much more than they will. The users will hardly notice the switch-over, if all goes to plan.

From Microsoft's point of view, WinRT/UWP is release-quality software, published to users since the year 2012, but from my point of view, UWP is still a big experiment. For me, UWP (including WinUI) is all a big beta-test version that I've been playing around with for years.

During the first few years of UWP, every year I thought: "errr… I'll wait until next year. There are still too many things in WPF that are missing in UWP. Surely next year will be better." Then the next year came and I repeated the same thought. Then the next year came and I repeated the same thought. Hopefully this year is the last year of saying that, or at least that's my intention.

WinUI can't afford more delays. Leave WinUI's DataGrid as C# code. Start writing more WinUI code in C# in order to increase productivity. It's now 8 years and Android has taken massive marketshare. That's a severe situation.