Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

nicolaihenriksen
Copy link
Contributor

@nicolaihenriksen nicolaihenriksen commented Feb 4, 2023

Fixes #3058
Fixes #3076

This PR extracts the TextBox.Padding setters out of the trigger collection and into the overriden Style instead. This allows the user to override them.

There is a consequence to this however: you now have to set the style, you cannot only set the attached properties. This is a visual breaking change. You can see how I needed to modify the MainWindow.xaml to get the correct behavior for the DemoItemsSearchBox.

There is also another (internal) consequence, which is that any trigger or similar which previously relied on the "hardcoded" padding for a particular style, now needs to respect any margin because the user can override it.

There is also the fact that this is not limited to the TextBox styles. If we decide to go this route, it should be fixed for all filled/outlined styles in a similar manner.

In the example below, I have set TextBox.Padding="5" on the SmartHint demo page (via a style setter) to illustrate that it is now possible to override in a style.
image

@nicolaihenriksen nicolaihenriksen marked this pull request as draft February 4, 2023 14:42
@nicolaihenriksen nicolaihenriksen changed the title TextBox: Respect externally set TextBox.Padding in triggers WIP: TextBox - Respect externally set TextBox.Padding in triggers Feb 4, 2023
@nicolaihenriksen nicolaihenriksen changed the title WIP: TextBox - Respect externally set TextBox.Padding in triggers TextBox: Respect externally set TextBox.Padding in triggers Feb 4, 2023
@nicolaihenriksen nicolaihenriksen marked this pull request as ready for review February 4, 2023 15:06
@nicolaihenriksen nicolaihenriksen marked this pull request as draft February 5, 2023 06:39
@nicolaihenriksen
Copy link
Contributor Author

@Keboo I converted it back to a draft because, although it solves the problem, I am not really happy with the solution.

Reason being that it violates the "principle of least astonishment". TextBox.Padding really should be an exact value representing the padding; not a partial one as it is in this PR.

The problem is that the triggers override the padding for the filled/outlined styles effectively ignoring any value set by the user. We could add attached properties for these paddings allowing the user to control the padding for these styles, but then it is still sort of strange that TextBox.Padding does nothing and the user would need to use the AP to set this for some styles and not for others.

Do you have a good idea on how to make the TextBox.Padding the only source of truth and still allowing the user to control it?

@Keboo
Copy link
Member

Keboo commented Feb 5, 2023

That is a good question. I do agree that combining two Thickness values together is not expected behavior. I am wondering with the 5.0.0 release if it might be worth getting rid of the attached properties and instead split the templates. Though I realize this is significantly more work.

@nicolaihenriksen nicolaihenriksen changed the title TextBox: Respect externally set TextBox.Padding in triggers WIP - TextBox: Respect externally set TextBox.Padding in triggers Feb 6, 2023
@nicolaihenriksen nicolaihenriksen added breaking change Items here have breaking API changes. visual breaking change Items here have affected the visual look of controls. and removed breaking change Items here have breaking API changes. labels Feb 6, 2023
@nicolaihenriksen
Copy link
Contributor Author

I am wondering with the 5.0.0 release if it might be worth getting rid of the attached properties and instead split the templates

After a good nights sleep, it finally dawned on me what I was doing wrong. I believe what needs to happen is that any "template-level" property (e.g. TextBox.Padding) we want to mutate for a given style, needs to be set in the style override rather than in the trigger collection. This gives the user a way of injecting their own overrides in between. I updated the code to reflect this approach. This has at least 2 consequences; see the updated PR description.

Whether we should split the templates is a good question. It would be a lot to maintain if nothing can be shared. Sharing between control templates is, to my knowledge, only really possible if you extract the shared XAML into an (internal) custom control for which we then define a template and expose whatever properties we need to be able to mutate. Personally I think we should try hard to stick with one template, and then perhaps not rely as much on the triggers (on attached properties) but rather explicitly override values in the style overrides. Thoughts?

@nicolaihenriksen
Copy link
Contributor Author

@Keboo See my comment above. Do you see this as a reasonable approach? If not, I won't bother implementing it for the remaining templates.

@Keboo
Copy link
Member

Keboo commented Feb 9, 2023

Hi @nicolaihenriksen sorry, I lost track of the notification on this one. YES! I completely overlooked that style of solution. You are absolutely correct, that if we use control template triggers they will make it quite difficult for people to override the values. I think this is an excellent solution.

Also extended the SmartHint demo to be able to toggle the HintAssit.IsFloating on/off.
@nicolaihenriksen
Copy link
Contributor Author

nicolaihenriksen commented Feb 10, 2023

YES! I completely overlooked that style of solution .... I think this is an excellent solution.

@Keboo I applied the same changes for the PasswordBox (also reveal style) and the ComboBox.

The DatePicker and TimePicker also contain a TextBox where I assumed a similar fix was needed, but the padding applied to the contained TextBox is done using a converter there, and I have checked that overriding the padding in an overridden style for the DatePicker/TimePicker works as expected.

Also, for the ComboBox, the outlined style does not use the default padding for the outlined TextBox, but rather a uniform 16px padding. This was already in place (set in the style override and not in a trigger), so I left it like it was; I only fixed the filled style which was done in the same way as the text boxes.

@nicolaihenriksen nicolaihenriksen changed the title WIP - TextBox: Respect externally set TextBox.Padding in triggers TextBox: Respect externally set TextBox.Padding in triggers Feb 10, 2023
@nicolaihenriksen nicolaihenriksen marked this pull request as ready for review February 10, 2023 20:06
@nicolaihenriksen nicolaihenriksen added this to the 4.8.0 milestone Feb 10, 2023
@Keboo Keboo added the release notes Items are likely to be highlighted in the release notes. label Feb 11, 2023
@Keboo Keboo merged commit e356f5d into MaterialDesignInXAML:master Feb 11, 2023
@nicolaihenriksen nicolaihenriksen deleted the fix3058 branch February 11, 2023 09:20
@nicolaihenriksen
Copy link
Contributor Author

and I have checked that overriding the padding in an overridden style for the DatePicker/TimePicker works as expected

@Keboo
Turns out that was a lie. Apparently I only checked it with an explicit padding applied on the element directly.

Also, there are some alignment issues with respect to the helper text. I think I may open up a "cleanup" PR to fix the padding issue for DatePicker/TimePicker and attack some of those helper text issues.

@Keboo
Copy link
Member

Keboo commented Feb 12, 2023

and I have checked that overriding the padding in an overridden style for the DatePicker/TimePicker works as expected

@Keboo Turns out that was a lie. Apparently I only checked it with an explicit padding applied on the element directly.

Also, there are some alignment issues with respect to the helper text. I think I may open up a "cleanup" PR to fix the padding issue for DatePicker/TimePicker and attack some of those helper text issues.

That would be awesome. Thank you!

@nicolaihenriksen
Copy link
Contributor Author

nicolaihenriksen commented Feb 14, 2023

That would be awesome. Thank you!

FINAL UPDATE
My apologies for the long writeups!!

I think I may have dug deep enough to see what is happening. It seems the intention of the TextFieldAssist.TextBoxViewMargin indeed is to adjust the margin of the "content" only. The AP callback looks for those elements by name. I think what is throwing me off a bit is the fact that the value of the AP is also directly mapped onto the Margin property of the SmartHint. I believe this latter part is wrong and should be removed. The AP should only control the margin of the content to adjust for alignment issues like with the RichTextBox (see update below). Alignment of hint, helper text and validation error should not have anything to do with this AP, but only consider the applied Padding. The AP is public and as such people can screw things up, but ideally they leave that AP alone and just rely on the values set in the templates. It could have been internal, but I assumes the intention with public is to allow for someone to make a complete local copy of the template which would not be possible with an internal AP. I hope you agree to this assesment?


@Keboo I think I may be missing some MDIX historical knowledge here, perhaps you can help me out. It is not entirely clear to me what the purpose of TextFieldAssist.TextBoxViewMargin is or was. The naming suggests something about being able to add a custom margin to the content part (e.g. PART_ContentHost) of a TextBox, possibly in order to ensure correct alignment of the hint text. However, it does not seem to be consistently applied to "content" across the different templates. Do you know its purpose in life? Is it really needed? Since I have refactored how the SmartHint is placed in some of the recent PRs, I may actually have introduced some regression in this area?!


UPDATE
It seems TextFieldAssist.TextBoxViewMargin is needed in the RichTextBox template because for some reason the PART_ContentHost (which allows entering characters) is offset by 4px for the RichTextBox compared to the normal TextBox. This actually complicates the alignment calculation even further, because the value should only be respected in some templates and not in others?!


Also, it kind of conflicts with TextBox.Padding which similarly is used to inject some space around the "content" of the TextBox. The AP is public, so not something that can simply be removed, but we could obsolete it and "make it do nothing". There may be some subtleties that I am overlooking where certain templates need minor tweaks to align hint and helper text correctly with the content, but in any case that should still respect the TextBox.Padding. So having the attached property as well just makes for one more variable that needs to be considered when placing the hint and helper text elements. Perhaps it would be easier to simply cut it out of the loop and only consider TextBox.Padding? We would probably need a converter for this (since it is most often only Margin.Left that is set to match the Padding.Left; not the whole Thickness). That converter could also take parameters to account for the special cases where a minor adjustment may be needed. Thoughts?

The values currently being used for the attached property are contributing to some of the slight misalignments of the hint and helper text that we're currently seeing. It is not a whole lot so I could do the PR without touching this AP, but I just worry that everything falls apart if a user sets a custom value for the AP because it is not respected/applied consistently.

In the GIF below you can see that the validation error does not respect the TextFieldAssist.TextBoxViewMargin (same for the helper text), and as such will make things look misaligned if set to non-default values:

TextBoxViewMargin2

@Keboo
Copy link
Member

Keboo commented Feb 15, 2023

I am going to spend some time on my stream tonight going through this. I agree this is quite complicated. I am not sure of the right answer, and I think I need to spend some time playing with the changes in your pull request.

@nicolaihenriksen
Copy link
Contributor Author

I think I need to spend some time playing with the changes in your pull request.

The changes currently in there only fix the overall scheme: hint and helper text should also follow padding (at least it seems so when looking at material.io).

I believe I know how to fix the remaining "minor misalignments" but don't have time to finish it before your stream.

Looking forward to see your stream.

@Keboo
Copy link
Member

Keboo commented Feb 15, 2023

Awesome. I will probably still spend some time playing with it just to make sure I understand everything. Really great work as always!

@nicolaihenriksen
Copy link
Contributor Author

Awesome. I will probably still spend some time playing with it just to make sure I understand everything. Really great work as always!

If you could look into whether you agree with ny assesment that TextFieldAssist.TextBoxViewMargin should only be used to manipulate PART_ContentHost (and similar) and NOT hints, helpers or validation, that would be awesome. Thats is at least what I think is the right approach. The remaining part is then about ensuring left edge of all those elements align nicely.

Another topic is the placement of helper and validation when HorizontalContentAlignment is Center or Right...

@Keboo
Copy link
Member

Keboo commented Feb 16, 2023

If you could look into whether you agree with ny assesment that TextFieldAssist.TextBoxViewMargin should only be used to manipulate PART_ContentHost (and similar) and NOT hints, helpers or validation, that would be awesome. Thats is at least what I think is the right approach. The remaining part is then about ensuring left edge of all those elements align nicely.

Yes, I believe only using TextFieldAssist.TextBoxViewMargin for the content host is correct.

Another topic is the placement of helper and validation when HorizontalContentAlignment is Center or Right...

I think those can be separate PRs, but I think they should follow the HorizontalContentAlignment. We should also consider FlowDirection.

@nicolaihenriksen
Copy link
Contributor Author

Yes, I believe only using TextFieldAssist.TextBoxViewMargin for the content host is correct.

Perfect, I will remove the "wrong usages" of it then.

I think those can be separate PRs, but I think they should follow the HorizontalContentAlignment. We should also consider FlowDirection.

Agree. I will create separate PRs for that and will also consider FlowDirection. Hopefully these templates (or at least the areas regarding hint/helper) are simple enough that "it just works", but I will be sure to test it.

On your stream you were debating whether an AP should be created to provide extra control over the placement of the hint/helper/validation. I agree this is a good idea; in fact I already added that for the hint in a previous PR - although that AP only affects the positioning when the hint floats. The AP is basically an enum with the values Inherit, Left, Center, Right, Stretch where Inherit is the default and this basically means it will follow the HorizontalContentAlignment.

Another minor thing. The demo app has both the Fields Line Up and the Smart Hint demo pages which are to some extent similar. I didn't actually change the Fields Line Up page, I just used it to demo the issues with the TextFieldAssist.TextBoxViewMargin AP. Anyway I think my other PR is ready for review now, so check it out and give the Smart Hint demo page a run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release notes Items are likely to be highlighted in the release notes. visual breaking change Items here have affected the visual look of controls.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Material Design 3 TextBox Height TextBox-padding defined in ResourceDictionary not worked
2 participants