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
MudTreeView: Fix selection issues #7810
MudTreeView: Fix selection issues #7810
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## dev #7810 +/- ##
==========================================
+ Coverage 87.18% 88.08% +0.90%
==========================================
Files 389 394 +5
Lines 11419 11770 +351
Branches 2299 2383 +84
==========================================
+ Hits 9956 10368 +412
+ Misses 966 874 -92
- Partials 497 528 +31 ☔ View full report in Codecov by Sentry. |
@ScarletKuro What do you think about the addition of |
Hi. Sorry for the delay.
If people ask for a method to select item from outside, then it makes sense. Also, shouldn't this method accept |
In
... and others we have the possibility to set a comparer, so yes, it should also be added as a parameter to |
It could be an optional parameter in the method, or an optional parameter in component itself, matter of taste. |
I would lean towards an optional parameter but I can also see why having it in the component could be beneficial. Happy with either way just let me know and I'll push a change. |
Also when looking in some other places of the code base I saw code like this to deal with using asnyc in a property setter: [Parameter]
[Category(CategoryTypes.FormComponent.Data)]
public DateTime? Date
{
get => _value;
set => SetDateAsync(value, true).AndForget();
} I think a similar technique could be employed to resolve the issues in the setter but if done wrong could cause issues in peoples projects. |
It should be in the component IMO because it can be used for the internal hashset. So if the parameter is supplied it should in any case be also supplied to the hashset. You'd want consistent equality in the component everywhere. |
This is not the only way. You could also use SetParametersAsync to call the setter and await it and it is probabably the better way of doing it. We only adopted this pattern very recently. |
This technique is not what we would like to use, since we want to get rid of it in future. |
Okay, so won't do the async in setter. Can you point me to an example of using SetParametersAsync to achieve this. Also trying to look this up online has lead me to a couple of stack overflow posts saying don't use SetParametersAsync, I would like to understand why I'm trying to learn more about blazor |
The argument against using |
In the example you gave would this mean Hidden was set evetime any other parameter in the component was set, this might be what Blazor is doing anyway. I guess the value wont change until the base is called so you could do a diff with value returned from Also the post I referenced talked about ParameterView going stale if you await in the method? Either way I'll have a play around tomorrow morning and see what I come up with. |
If you have to await more than one method because more than one parameter changed you could just add the tasks into a list and await them with |
@henon and @ScarletKuro made a few changes, but it did trigger a few more questions. The code I've commit works with my testing, when I set SelectedValue in my app it gets set as you would expect, but how should this interact with the MudTreeViewItem selected item. If someone manually changes the selected value of a tree item should we try and listed for the changes and reflect that in the SelectedValue. There is also a question about what to do it someone set selected value to an invalid option, not figured out a nice way to handle this. I've also not done the compare part yet. |
I don't know much about treeview as it was coded by someone else but in any case the internal state of the component should remain consistent no matter which method was used to manipulate it. I hope that helps you with this question. |
I think the selected value should then be |
@henon and @ScarletKuro I think everything is done now, take a look when you have time. |
@henon I've added a test to cover the most of the code I've written the only no covered code is a guard clause that I don't think it's possible to trigger but catches a possible null issues. Is this okay to go in, if so how? not too sure on the process yet. |
Good job @jacob7395, thank you very much for your efforts! |
And to answer your question, yes, sometimes some errorhandling statements can not be tested without extreme efforts. That is OK. It is not worth the effort mostly. |
Thank you both for your help, I learned a lot from this one. The stuff around not using property setters for parameters is really interesting. |
I deleted my comments from earlier today and was able to determine it was a visibility/async issue on my end causing this enhancement to break my existing code. Binding the SelectedValue now works great and highlights the node! Thanks for the long-needed enhancement! I was able to remove all my "work around" code for this issue. :) |
I'm guessing this resulted in the In this example, I feed the <MudTreeView @ref="_mudTree" T="TreeItemData" Items="_treeItems" SelectedValue="_selectedItem" SelectedValueChanged="OnSelectedItemChanged">
<ItemTemplate>
<MudTreeViewItem Value="@context" Text="@context.Name" />
</ItemTemplate>
</MudTreeView> private HashSet<TreeItemData> _treeItems = new HashSet<TreeItemData>();
public class TreeItemData
{
public MyObject MyObject { get; set; }
public HashSet<TreeItemData> TreeItems { get; set; } = new HashSet<TreeItemData>();
public TreeItemData(MyObject myObject)
{
MyObject = myObject;
}
} I'm having trouble programatically setting the |
You mean the |
There's an exposed public async Task Select(MudTreeViewItem<T> item, bool isSelected = true)
{
if (MultiSelection)
{
await item.Select(isSelected);
await SelectedValuesChanged.InvokeAsync(SelectedValues);
return;
}
if (isSelected)
{
await SetSelectedValue(item.Value);
return;
}
await SetSelectedValue(default);
} This looks like what we want, but it's asking for a My scenario is this:
|
You can look the code, for example the tests, one of the examples: <MudTreeView @ref="_treeView" T="string" @bind-SelectedValue="selectedValue">
<MudTreeViewItem @ref="_item1" Value='"content"' />
<MudTreeViewItem @ref="_item2" Value='"src"' />
</MudTreeView>
@code {
MudTreeView<string> _treeView;
MudTreeViewItem<string> _item1;
MudTreeViewItem<string> _item2;
public string selectedValue;
public async Task SelectFirst()
{
await _treeView.Select(_item1);
}
public async Task SelectSecond()
{
await _treeView.Select(_item2);
}
public async Task DeselectSecond()
{
await _treeView.Select(_item2, false);
}
} |
In |
We should, but i feel like TreeView requires 90% code drop, it's just all way around wrong. |
I'll rewrite it completely when I'm done with MudList where I want to do some small improvements. This component was contributed by a non-active member anyway, so it is about time we consolidate it. |
I can post the Expanded and Selected proerties change if u want |
How about you just PR it and I continue from there? |
Thanks for looking into all of this. If you are going to rewrite, I'd also like to mention that virtualization is essential for this type of component. As it stands, if you expand too many nodes it'll bog down your app. |
@kelltom sure, but that'll be a separate work item and if you could help with that (once we got the breaking changes done in v7) that would be great. |
@kelltom I just found out that No need to use this: |
Oh, sorry, it doesn't work when you initialize the selected value in the bound variable. I will fix that. |
* MudTreeView: Added method to set the selected items to a value<T> * feature: added parameter to set custom comparator
Description
closes #5704
closes #4492
closes #3394
This PR addresses issues #5704, #4492, #3394, and follows on from PR #5856. By tackling bind issues with IsSelected. Given the challenges of integrating async methods into property setters, I've introduced a new method:
This method is designed to find a given value within the tree and execute the necessary selection logic. I'm seeking feedback on this approach, particularly regarding the following points:
Current usage of SelectedValue as an update event may be misleading due to the lack of a straightforward two-way bind. Would replacing this with a callback method and adding documentation for clarification be a best practice?
A new parameter
Comparer
was also added in the process.How Has This Been Tested?
Unit tests are planned to cover these changes. I’m looking for feedback on the approach before proceeding with test implementation.
Types of changes
The visual change is the same as in #5856.
Checklist:
dev
).