-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GridSplitter: Make IsTabStop work and simplify control's visual tree #1145
Conversation
@@ -22,30 +24,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls | |||
/// </summary> | |||
public partial class GridSplitter | |||
{ | |||
// Symbols for GripperBar in Segoe MDL2 Assets | |||
private const string GripperBarVertical = "\xE784"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These styles should be applied within the control style and visual states instead of here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be possible to move the gripper content into the control template and use visual states for selecting the right content. But then it would always be shown and we would lose the functionality of easily overriding the gripper content by using the "Element" property. This would be a breaking change. We would have to remove the Element property, and our users would instead have to override the control template for custom content. I do not think that this is a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the control allows for content then it should be a ContentControl. I would suggest changing to a ContentControl, mark Element as deprecated and when it changes set the content to be the value. Default the content to be the style proposed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to agree with Shawn it should have been a content control from the beginning (but of course not my bad :P )
We can do it right with a small change, just moving the textbox to the grid inside the control template and set the textbox value based on orientation on splitter loaded.
I see no need to move GripperBarVertical to visual state as it should be used only twice once on splitter loaded and when the splitter orientation change to update the gripper with the new value (which is not currently implemented)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do the right thing :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nearest case for the splitter is Button control wish is a ContentControl that allows custom content to change the way it looks :)
Anyway, I see we can consider moving the splitter from using Element to ContentControl in V2 so we don't have to use DEPRECATED keyword with a change that doesn't add extra functionality.
Will review the PR this weekend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see it like that. A button's main purpose is to show content and allow you to click it. Each button in your UI will usually show different content. So unlike the GridSplitter, showing custom content is inherent part of the button's functionality. Much like a checkbox, which is there to show content and allow you to check it. The gripper is more like the checkmark of a checkbox. It is part of the style which is usually the same for all instances of the control. It is not like the content of a checkbox.
But well, just because I don't think it should be a ContentControl, that surely does not mean you cannot make it one :) It's just my opinion on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@skendrot It would be great if you could approve the PR. Please see the discussion above. If someone wants to do a redesign of the GridSplitter control, please create a separate issue/PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@skendrot I juse see that @IbraheemOsama has already created an issue for changing the control to ContentControl. Then my PR should be ready to go?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with waiting to change the control. However:
If we plan to keep the concept that it will allow custom content (via the Element property or by making it a ContentControl), then let's embrace that now. Instead of having an internal textblock, set that to be the Element property and change the text based on a visual state.
Or do we want to remove the capability to allow custom content (eg: Remove Element property and do not change to be a ContentControl), which I think is also a valid solution and is how the WPF GridSplitter behaved. This option would probably need to be done in the 2.0 release.
var gripper = sender as GridSplitterGripper; | ||
|
||
if (gripper == null) | ||
if (_gripperDisplay == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this check as _gripperDisplay will always be null if this function is reached
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Loaded event can fire multiple times. It is called each time a control is (re-)added to the visual tree. For example if you use a Frame with page caching and navigate to a different page, the old page content will get Unloaded event and then is put into cache. When moving back to the old page, it is re-added to the visual tree and so it will get Loaded event again, for the second time. In that case, our _gripperDisplay already exists, no need for us to re-create it.
HorizontalAlignment = HorizontalAlignment.Center, | ||
VerticalAlignment = VerticalAlignment.Center, | ||
Foreground = GripperForeground, | ||
Text = gripperText |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this variable can be replace with it's value directly, no need to create a new variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If expressions get too long, I sometimes like to introduce a separate variable to keep lines shorten. But I will chage as you suggested.
|
||
private void GridSplitter_KeyDown(object sender, KeyRoutedEventArgs e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about override on key down instead of registering new event ?
`
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
var step = 1;
var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
if (ctrl.HasFlag(CoreVirtualKeyStates.Down))
{
step = 5;
}
if (_resizeDirection == GridResizeDirection.Columns)
{
if (e.Key == VirtualKey.Left)
{
HorizontalMove(-step);
}
else if (e.Key == VirtualKey.Right)
{
HorizontalMove(step);
}
else
{
return;
}
e.Handled = true;
return;
}
if (_resizeDirection == GridResizeDirection.Rows)
{
if (e.Key == VirtualKey.Up)
{
VerticalMove(-step);
}
else if (e.Key == VirtualKey.Down)
{
VerticalMove(step);
}
else
{
return;
}
e.Handled = true;
}
base.OnKeyDown(e);
}
`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I can do that.
@@ -174,9 +175,11 @@ protected override void OnApplyTemplate() | |||
|
|||
// Unhook registered events | |||
Loaded -= GridSplitter_Loaded; | |||
KeyDown -= GridSplitter_KeyDown; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed in favor of overriding Keydown event
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
|
||
// Register Events | ||
Loaded += GridSplitter_Loaded; | ||
KeyDown += GridSplitter_KeyDown; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
@@ -180,10 +181,10 @@ public SplitterCursorBehavior CursorBehavior | |||
private static void OnGripperForegroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |||
{ | |||
var gridSplitter = (GridSplitter)d; | |||
var grip = gridSplitter.Element as GridSplitterGripper; | |||
var grip = gridSplitter._gripperDisplay; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change variable grip to gripper to match the rest of the control ?
I know it is an old code :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure
@lukasf LGTM but method OnKeyDown is missing it's comment, you can use |
@IbraheemOsama Thanks, I added the missing comment. |
@skendrot, now that we created a new issue for changing the control to ContentControl, anything missing in the PR before you sign off? |
Sorry. It looks like I typed a comment but never submitted it!
|
@skendrot Can we please move the discussion on how to handle Content (now and in future) to the new issue submitted by @IbraheemOsama and close this PR? I am just trying to fix a problem with the control. I did not invent the Element stuff, and I did not change how it is done. It was an internal TextBlock before and it still is now, i just moved that code to a different place. I understand that you guys want to redesign that stuff, please go ahead, a separate issue has already been created for that. |
You're right @lukasf. |
Thank you. |
This is to resolve #1143.
GridSplitterGripper was removed, keyboard events are now taken on top level control. I have checked that the control behaves exactly the same, including custom gripper content and "auto content" based on alignment.