-
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
[Feature] Microsoft.Toolkit.Mvvm package (Preview 2) #3429
[Feature] Microsoft.Toolkit.Mvvm package (Preview 2) #3429
Conversation
Thanks Sergio0694 for opening a Pull Request! The reviewers will test the PR and highlight if there is any conflict or changes required. If the PR is approved we will proceed to merge the pull request 🙌 |
Looks like the changes in 1cb4df2 uncovered a bug in the .NET Native compiler, so the build is now failing in Release UWP 🤦♂️
I managed to isolate the issue in the custom public delegate ref T FieldAccessor<T>();
private int n;
private void Button_OnClick(object sender, RoutedEventArgs e)
{
FieldAccessor<int> accessor = () => ref n;
accessor() = default;
} I've also prepared a repro project which you can find here: FieldAccessorRepro.zip. Will create a full .NET Native repro to send to the team, but in the meantime I was wondering whether @MichalStrehovsky or @tommcdon might have some ideas of how to work around the issue on the UWP end? Maybe some |
Regression to unblock UWP for now, see dotnet/corert#8273
@msftbot make sure @stevenbrix reviews before merging |
Hello @michael-hawker! Because you've given me some instructions on how to help merge this pull request, I'll be modifying my merge approach. Here's how I understand your requirements for merging this pull request:
If this doesn't seem right to you, you can tell me to cancel these instructions and use the auto-merge policy that has been configured for this repository. Try telling me "forget everything I just told you". |
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.
Looks fairly good. Most comments are around validation of unset required properties. I feel like those should be considered invalid. There is a Validator.TryValidateObject method you can use to validate the whole model.
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private IEnumerable GetAllErrors() | ||
{ | ||
return this.errors.Values.SelectMany(errors => errors); |
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 do we do for properties marked Required?
If those fields are null, should we consider them errors?
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.
So, I have to say I'm not 100% I understand the official documentation here.
From the MS docs:
GetErrors
: Gets the validation errors for a specified property or for the entire entity.
I read that as "get/retrieve the currently stored errors for either a specific property or for the entity (so for all properties)", as in, return the errors that have previously been computed, without actually doing any validation now. By that logic, the code right now is just returning the existing errors corresponding to the input query 🤔
I mean, that makes sense to me since we expose a separate method to actually validate properties and update errors, which is ValidateProperty
, but I have to say with how the docs are currently phrased that's not entirely clear.
I guess the question is - should GetErrors
just return existing errors for a given query, or actually perform a new validation for a given property (or all properties, if the whole entity is targeted)? Thoughts?
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 agree, the docs aren't clear. I imagine, like many things, it's up to us to define the behavior.
Edit: I saw your samples below, and realized this behavior is correct :)
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.
Some bug in GitHub is causing me to not be able to comment on this further down. But basically, I don't feel like a ValidateProperty
method should be required. Can ObservableValidator
override the SetProperty
method and call ValidateProperty
itself?
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.
But, at the end of the day - I think this ok. When a user opens up a form, we don't want a bunch of errors for fields they haven't entered anything into yet
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 fold ValidateProperty
into the SetProperty
method? Those should always go hand-in-hand.
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.
Done in 28b1977 as discussed on Discord 👍
{ | ||
if (errorsChanged) | ||
{ | ||
this.totalErrors--; |
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 not exactly sure what this count value is for. Can we not use the errors dictionary as the source of truth?
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've added an XML comment for that here:
My idea here was - with how the code is currently setup, the dictionary can contain entries for valid properties, just with the list of errors being empty (so that we can reuse the same List<ValidationResult>
instances when possible. So in order to check whether we have errors, we'd have to traverse the entire dictionary and check whether all values are empty lists (or if no entries are there at all). This would have a cast of O(N)
, as you'd have to traverse the entire dictionary once to check all properties, and the dictionary could potentially contain all the existing properties for a given object. So the point of this additional field, which is kept in sync with the dictionary, is to provide a fast O(1)
accessor to quickly check whether or not there are any errors in the current instance.
Let me know what you think! 😊
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 appreciate the attention to perf, but how often do we expect errors to transition between valid/invalid?
My gut is that we won't really be allocating that often to warrant this extra bit of complexity and size trade off. Computers are much faster at allocating/deallocating memory than humans are at typing :)
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.
Yeah that's a good point, I've removed the field in e7a4824 😊
Hello @msftbot[bot]! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
This PR has been marked as "needs attention 👋" and awaiting a response from the team. |
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.
Overall looks good!
The only thing I would suggest is to remove the ValidateProperty
method. There is already the Validator
class.
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private IEnumerable GetAllErrors() | ||
{ | ||
return this.errors.Values.SelectMany(errors => errors); |
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.
Some bug in GitHub is causing me to not be able to comment on this further down. But basically, I don't feel like a ValidateProperty
method should be required. Can ObservableValidator
override the SetProperty
method and call ValidateProperty
itself?
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private IEnumerable GetAllErrors() | ||
{ | ||
return this.errors.Values.SelectMany(errors => errors); |
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.
But, at the end of the day - I think this ok. When a user opens up a form, we don't want a bunch of errors for fields they haven't entered anything into yet
[MethodImpl(MethodImplOptions.NoInlining)] | ||
private IEnumerable GetAllErrors() | ||
{ | ||
return this.errors.Values.SelectMany(errors => errors); |
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 fold ValidateProperty
into the SetProperty
method? Those should always go hand-in-hand.
This PR has been marked as "needs attention 👋" and awaiting a response from the team. |
And part 1 is done! Thanks @stevenbrix for the help! 🎉🎉🎉 |
Closes #3428
PR Type
What kind of change does this PR introduce?
Overview
This PR is used to track and implement new features and tweaks for the
Microsoft.Toolkit.Mvvm
package.See the linked issue for more info, and for a full list of changes included in this PR.
PR Checklist
Please check if your PR fulfills the following requirements: