Skip to content
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

Merged
merged 3 commits into from
May 30, 2017

Conversation

lukasf
Copy link
Contributor

@lukasf lukasf commented May 3, 2017

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.

@@ -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";
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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

Copy link
Member

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)

Copy link
Member

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 :)

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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)
Copy link
Member

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

Copy link
Contributor Author

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
Copy link
Member

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.

Copy link
Contributor Author

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)
Copy link
Member

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);
    }

`

Copy link
Contributor Author

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;
Copy link
Member

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

Copy link
Contributor Author

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Copy link
Contributor Author

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;
Copy link
Member

@IbraheemOsama IbraheemOsama May 6, 2017

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 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

@IbraheemOsama
Copy link
Member

IbraheemOsama commented May 13, 2017

@lukasf LGTM but method OnKeyDown is missing it's comment, you can use
/// <inheritdoc />

@lukasf
Copy link
Contributor Author

lukasf commented May 16, 2017

@IbraheemOsama Thanks, I added the missing comment.

@nmetulev
Copy link
Contributor

@skendrot, now that we created a new issue for changing the control to ContentControl, anything missing in the PR before you sign off?

@skendrot
Copy link
Contributor

Sorry. It looks like I typed a comment but never submitted it!

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.

@lukasf
Copy link
Contributor Author

lukasf commented May 30, 2017

@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.

@skendrot
Copy link
Contributor

You're right @lukasf.

@lukasf
Copy link
Contributor Author

lukasf commented May 30, 2017

Thank you.

@nmetulev nmetulev merged commit 29e9f8b into CommunityToolkit:dev May 30, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants