MudTreeView: Use ParameterState and rewrite selection logic from scratch + new features#8661
MudTreeView: Use ParameterState and rewrite selection logic from scratch + new features#8661ScarletKuro merged 50 commits intoMudBlazor:devfrom
Conversation
|
Commented out the |
|
Removed |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #8661 +/- ##
==========================================
+ Coverage 89.82% 90.10% +0.27%
==========================================
Files 412 417 +5
Lines 11878 12127 +249
Branches 2364 2388 +24
==========================================
+ Hits 10670 10927 +257
+ Misses 681 663 -18
- Partials 527 537 +10 ☔ View full report in Codecov by Sentry. |
|
@ScarletKuro I know it's kind of a little unrelated here, but while you are working on MudTreeView, I do not understand why pull request #4556 was closed, but the Is this off topic for V7? |
|
if we do same for +private readonly ParameterState<bool> _activatedState;
+_activatedState = RegisterParameterBuilder<bool>(nameof(Activated))
+ .WithParameter(() => Activated)
+ .WithEventCallback(() => ActivatedChanged)
+ .WithChangeHandler(OnActivatedParameterChangedAsync);
-public bool Activated
-{
- get => _isSelected;
- set
- {
- if (_isSelected.Equals(value)) return;
-
- _isSelected = value;
- }
-}
+public bool Activated { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
- if (firstRender && _isSelected)
+ if (firstRender && _activatedState.Value)
-public override async Task SetParametersAsync(ParameterView parameters)
+private Task OnActivatedParameterChangedAsync(ParameterChangedEventArgs<bool> arg)
+{
+ if (MudTreeRoot is null)
+ {
+ if (MudTreeRoot is not null)
+ {
+ await MudTreeRoot.Select(this, previousActivatedValue);
+ }
+ return Task.CompletedTask;
+ }
+
+ return MudTreeRoot.Select(this, arg.Value);
+}
-if (item.Activated)
+item.GetState<bool>(nameof(MudTreeViewItem<T>.Activated))
other changes replacing _isSelected on _activatedState.ValueThen at first glance it seems to work, but when playing with You will notice than sometimes you need to double click for the node to be activated, and the test then it will pass. It was really late for me, and I haven't found the reason yet. |
No, we'll change to IReadOnlyCollection just like in MudChipSet which I just reworked the same way. |
|
Hi @belucha,
This PR was created in 2022 when breaking changes were not acceptable, therefore it was closed. Also, this PR is now not against the latest code base.
Because we only started to work on new version, obviously we can't change everything at once. We address things by the matter of the priority. The |
|
@henon great! |
|
Added another example and found a bug |
|
I will re double check everything at night |
Keep it mind, that if you will hot swap the Comparer and the SelecteValueS it will not work as expected as the special case I mentioned before will not work with this We would need to add something like this public RegisterParameterBuilder<T> WithComparer<TFrom>(Func<IEqualityComparer<TFrom>> comparerFromFunc, Func<IEqualityComparer<TFrom>, IEqualityComparer<T>> comparerToFunc, [CallerArgumentExpression(nameof(comparerFromFunc))] string? comparerParameterName = null)
{
_comparerFunc = () => comparerToFunc(comparerFromFunc());
_comparerParameterName = comparerParameterName;
return this;
}
.WithComparer<T?>(() => Comparer, x=> new CollectionComparer<T>(x));But I would also need to store somewhere the otherwise this line will just throw with cannot convert from IEqualityComparer<IReadOnlyCollection> to something something. This is kind of troublesome for now. upd: another solution would be just to use two compares for single and multiple selection, since wrapping another |
Why not? Sorry I don't understand and I didn't understand the special case you are talking about. Don't you call the func for every comparison? The only concern is that a new collection comparer is created on every comparison but it would always be up to date with the latest |
I described it here #8629 in the Support for Func<IEqualityComparer> and there is even SS and bUnit tests that
Yes, that's what func does. However, when the |
|
oh, so instead of calling the func you try to find the comparer in the parameterview to get the latest value? |
|
... or if you don't find the comparer in the view just call the func. This whole thing is a very carefully crafted academic problem that will never ever happen in reality. nobody switches comparers in the middle of the life-time of the component and we could even forbid it to make sure. Then the problem is limited only to initialization where it can be handled by simply consolidating the initial parameter values with the Comparer in OnAfterRender. |
I think this would be the best and easiest to implement.
It's already doing so.
Yes, this is what I wanted to say, this is a very niche problem that is very unlikely to happen, so you shouldn't worry about it, and this is why I don't want to make it more complicated than it should be. But I just wanted to let you know, so there not just me who knows the nuances :) It's better when multiple people carries the knowledge for future. |
|
@henon awesome work, thanks |
After sleeping over with this, I found relatively easy solution how the implementation can look like without overhauling directly the public RegisterParameterBuilder<T> WithComparer<TFrom>(Func<IEqualityComparer<TFrom>> comparerFromFunc, Func<IEqualityComparer<TFrom>, IEqualityComparer<T>> comparerToFunc, [CallerArgumentExpression(nameof(comparerFromFunc))] string? comparerParameterName = null)
{
_comparer = new ParameterEqualityComparerTransformSwappable<TFrom, T>(comparerFromFunc, comparerToFunc);
_comparerParameterName = comparerParameterName;
return this;
}And instead of this usage: .WithComparer(x => new CollectionComparer<T>(Comparer));It's: .WithComparer(() => Comparer, x => new CollectionComparer<T>(x));When you don't need any transformation the old syntax stays .WithComparer(() => Comparer);And the unit tests shows that it does solve the problem and doesn't break the existing logic. I just thought it would be "nice" to have, because I saw that |
|
Just wanted to chime in here with a few questions:
Apologies if any of this was obvious from previous discussion, I haven't really had time to dive in yet. This weekend I plan to get versed in MudBlazor contribution so I can make better sense of this stuff. Thanks, and nice work! |
Yes. But not via
This PR doesn't. But I think this is a very useful functionality and we can implement it fairly easily in a follow-up PR. |
That part should be unnecessary since Blazor should do it automatically.
I think such public API should be prohibited in most cases, and it's good thing we removed them. |
I would agree. Bit of an oversight on my part. This would be ideal for sure. Looking good! |
Of course, when the bound variable is set by another component via two-way binding or in an event handler of a blazor component. There are other cases (in a background thread, timer, etc), where you need to start a render manually in order to update the selected value after setting the variable you bound to |
…tch + new features (MudBlazor#8661) Co-authored-by: Meinrad Recheis <[email protected]>

Description
resolves #8360
resolves #8209
resolves #6132
resolves #5853
resolves #4536
resolves #4261
resolves #4105
resolves #2093
resolves #1522 by not allowing to mess with items ;)
resolves #1511
Breaking Changes
ReadOnlyfor a non-selectable treeview.Multiselectionhas been replaced by parameterSelectionModewith enum values{ SingleSelection, MultiSelection, ToggleSelection }Itemsnow usesIReadOnlyCollection<T>Activedwas removed. UseSelectedinsteadExpandedIconwas removed. UseExpandButtonIconinsteadItemsandServerDatanow useIReadOnlyCollection<T>Warning
MudTreeViewItem: Parameter
ExpandedIconwas removed. UseExpandButtonIconinstead to set a custom glyph for the expand button. This is not to be confused with the new parameterIconExpandedwhich is a new feature to allow showing an alternate icon in expanded state instead ofIcon. #8661Bug Fixes
SelectedValueorSelectedValuesnow initializes the SelectedState state of the items.New Features
TriStateset to true the checkboxes in multi-selection display indeterminate state if their sub-item's Selected state does not agree with theirs. The parent item'sSelectedstate is not affected by this, it is just a visualization.SelectedValuesforMultiSelectionIconExpandedis shown instead ofIconif the item is expanded.How Has This Been Tested?
Unit Tests
Types of changes
Checklist
dev).Documentation Overhaul