Microsoft-ui-xaml: Question: What is the best way to build an Excel like layout?

Created on 28 Sep 2020  路  15Comments  路  Source: microsoft/microsoft-ui-xaml

Hello!

I am finding a way to build an "Excel like" layout.

image

The key features of that scenario is:

  • Left content should be vertically scrolled synchronously with a main content. At the same time it should not be scrolled horizontally (fixed columns in Excel)
  • Top content should be horizontally scrolled but not vertically.
  • The scroll bars can be anywhere.

For-example, the horizontal scrollbar on Excel`s screen bellow is not fit the whole width.

image

My first solution I tried was a grid with two panels for the Left and Top content, and a ScrollViewer with an ItemsRepeater for the main content. I invalidate the panel`s measure on ScrollViewer.ViewChanged event and perform the layout in each panels on measure pass according to the current RealizationRect. This approach looks like work, but now I need to change the position of the scrollbars.

To do this I am going to change the template of the ScrollViewer. But now I think, is there any best solution to do this? Am I going true way?

area-ItemsRepeater area-Scrolling question

Most helpful comment

@Sergio0694 added some ScrollViewer extensions in the last version of the Toolkit which I think may be helpful here?

All 15 comments

That is an interesting problem. There are a few things here, so I'll split my opinion up based on the different things:

Columns/Rows persistence

I think you can only achieve this by having the cells themselfes in a ScrollViewer and have on vertical scrollviewer for the Rows headers and one horizontal scrollviewer for the column headers. When the view of your "cells view" changes, you would then need to adjust the scroll position of the rows and and columns header ScrollViews. Unfortunatly, ScrollViewer doesn't allow having fixed content, so this solution with the ViewChanged might be the only option here.

Positionion of scrollbars

I think you are right that retemplating the ScrollViewer here is the easiest solution to allow scrollbar to be placed like in the screenshot.

Thank you, @chingucoding. Unfortunatelly, I tried to use three ScrollViewers and sync it. But at this case I cant to avoid of independed animations. When I, for-example, perform the scrolling by mouse wheel, the content of the main area goes faster than the top and left contents. Seems ViewChanged raises too late. I understand, that I cant jump through the independent animations.

Anyway, I found the TopHeader, LeftHeader, TopLeftHeader properties on the ScrollViewer. Seems they work exactly as I want. But, it is impossible to make fixed columns/headers at the right/bottom side.

I wonder if this could be solved by composition layer?

Anyway, I found the TopHeader, LeftHeader, TopLeftHeader properties on the ScrollViewer. Seems they work exactly as I want. But, it is impossible to make fixed columns/headers at the right/bottom side.

I did not know that, awesome that those are just what you need!

I wonder if this could be solved by composition layer?

What do you mean by composition layer? If you want to change the position of the scrollbar and also change the width, I think you'll need to retemplate. If you just overlay the tabs (as excel does), how would you solve the overlapping of content?

What do you mean by composition layer? If you want to change the position of the scrollbar and also change the width, I think you'll need to retemplate. If you just overlay the tabs (as excel does), how would you solve the overlapping of content?

As for the scrollbar position, I will try to retemlate, thank you!

As for the composition layer.
TopHeader and LeftHeader properties allow me to set a fixed content for the top and left part. But I want to have the ability to make fixed the right and bottom parts also. The main disadvantage of any approaches with a part syncs on ViewChanged is the gap between render and UI threads. I think the solution would be to move the fixed content to ScrollViewer content (in some custom panel), and than try to correct position of fixed content by binding to the scroll viewers properties in composition layer. Does it make sence?

TopHeader and LeftHeader properties allow me to set a fixed content for the top and left part. But I want to have the ability to make fixed the right and bottom parts also. The main disadvantage of any approaches with a part syncs on ViewChanged is the gap between render and UI threads. I think the solution would be to move the fixed content to ScrollViewer content (in some custom panel), and than try to correct position of fixed content by binding to the scroll viewers properties in composition layer. Does it make sence?

Right I see. Composition layers could work. Depending on how you will render your table (or inner content), you might also be able to make it work by writing some kind of custom layout that returns the correct "border" and scrolls the inner content. The composition approach could definitely work, however I am not sure how tight the loops are when changing positions so you might have synchronization issues?

@RBrid is an expert on the ScrollView(er), maybe he has any ideas how to approach this the best.

however I am not sure how tight the loops are when changing positions so you might have synchronization issues?

Here is scrolling in my sample project. The yellow column is the left panel which is sync with a scroll viewer content on view changed.

The gap is significant.

https://i.imgur.com/ru55Ed4.gif

Hmm that is really a significant gap, not sure if adding bottom and right headers with the view changed event will look good. Composition might make it better, but I think the main bottle neck is just the event not being fast enough.

@Sergio0694 added some ScrollViewer extensions in the last version of the Toolkit which I think may be helpful here?

Yeah this seems like a very good use case scenario for those extensions, possibly in combination with the ClipHelper extension too to make sure the scrolled visuals are clipped in the target areas 馃憤

I'm using a very similar setup in my own app and it's working pretty well, so I'd say definitely worth a try!

I`ve tried to pin header by composition animation.

image

It works perfect when I perform scrolling by mouse wheel

https://i.imgur.com/Oi4DwOM.gif

But if I drag a thumb of vertical scrollbar, the text becomes blury and jumps.

https://i.imgur.com/Gl80atG.gif

I tried to round expression

_expression.Expression = "-Round(ScrollManipulation.Translation.Y)";

After that I saw the oposite behaviour. The text stays stable on scrolling by the thumb, but blures and jumps on scrolling by wheel ((

Any ideas?

@BorzillaR I don't really understand what's going on from those small GIFs you posted, but I put together a small sample of a similar UI using the scrollviewer extensions from the toolkit, as well as the clip helper, is this similar to what you had in mind?

WpwPhicgC3

In this case it's all working as expected for me both with the mouse wheel and the scroll thumbs.
I can share the code if you need! 馃槉

@RBrid might have some thoughts here.

@Sergio0694, follow the yelow text behaviour on my last gif, please.

I taked some screens where it cleary visible what is going on. Notice, that the yellow text is blured at the first screen. On the second screen all is ok with bluring, but the position of the text is changed to one pixel up. On the last screen the text has the both artefacts (position and bluring)

image

I can share the code if you need! 馃槉

Yes, please, I will be grateful to you!

@BorzillaR Here's the sample from that GIF I posted, hope this helps! 馃槃

GridScrollerSample.zip

@Sergio0694, thank you!

Was this page helpful?
0 / 5 - 0 ratings