How do I get the selected item in the BindableListView? #43
-
A common scenario in my application is to have a list of items, where one could be selected by the user (e.g. clicked) and then the information about that item (e.g. description) would be displayed in a neaby The question is: how do I get the selected item in the |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
There are two approaches, with and without the UnityMvvmToolkit.Generator. Let's say we have the following ViewModels. MyItemViewModel with UnityMvvmToolkit.Generatorpublic partial class MyItemViewModel : ICollectionItem
{
public MyItemViewModel()
{
Id = Guid.NewGuid().GetHashCode();
}
public int Id { get; }
[WithObservableBackingField]
public string Name
{
get => _name.Value;
set => _name.Value = value;
}
} MyItemViewModel without UnityMvvmToolkit.Generatorpublic partial class MyItemViewModel : ICollectionItem
{
private readonly IProperty<string> _name = new Property<string>();
public MyItemViewModel()
{
Id = Guid.NewGuid().GetHashCode();
}
public int Id { get; }
public string Name
{
get => _name.Value;
set => _name.Value = value;
}
} public class MyViewModel : IBindingContext
{
[Observable]
private readonly IProperty<MyItemViewModel> _selectedItem;
[Observable]
private readonly IReadOnlyProperty<ObservableCollection<MyItemViewModel>> _items;
public MyViewModel()
{
var items = new ObservableCollection<MyItemViewModel>
{
new() { Name = "My Item 1" },
new() { Name = "My Item 2" },
new() { Name = "My Item 3" },
};
_items = new ReadOnlyProperty<ObservableCollection<MyItemViewModel>>(items);
_selectedItem = new Property<MyItemViewModel>();
}
} Then we have to create a MyListView with UnityMvvmToolkit.Generator[BindableElement]
public partial class MyListView : BindableListView<MyItemViewModel>
{
[BindableProperty("SelectedItem")]
private IProperty<MyItemViewModel> _selectedItem;
partial void AfterSetBindingContext(IBindingContext context, IObjectProvider objectProvider)
{
onSelectionChange += OnSelectionChange;
}
partial void AfterResetBindingContext(IObjectProvider objectProvider)
{
onSelectionChange -= OnSelectionChange;
}
private void OnSelectionChange(IEnumerable<object> obj)
{
_selectedItem.Value = (MyItemViewModel) selectedItem;
}
} MyListView without UnityMvvmToolkit.Generatorpublic class MyListView : BindableListView<MyItemViewModel>
{
private PropertyBindingData _selectedItemBindingData;
private IProperty<MyItemViewModel> _selectedItem;
public override void SetBindingContext(IBindingContext context, IObjectProvider objectProvider)
{
base.SetBindingContext(context, objectProvider);
if (string.IsNullOrWhiteSpace(BindingSelectedItemPath) == false)
{
_selectedItemBindingData ??= BindingSelectedItemPath.ToPropertyBindingData();
_selectedItem = objectProvider.RentProperty<MyItemViewModel>(context, _selectedItemBindingData!);
}
onSelectionChange += OnSelectionChange;
}
public override void ResetBindingContext(IObjectProvider objectProvider)
{
if (_selectedItem is not null)
{
objectProvider.ReturnProperty(_selectedItem);
_selectedItem = null;
}
base.ResetBindingContext(objectProvider);
onSelectionChange -= OnSelectionChange;
}
private void OnSelectionChange(IEnumerable<object> obj)
{
_selectedItem.Value = (MyItemViewModel) selectedItem;
}
private string BindingSelectedItemPath { get; set; }
public new class UxmlFactory : UxmlFactory<MyListView, UxmlTraits> { }
public new class UxmlTraits : BindableListView<MyItemViewModel>.UxmlTraits
{
private readonly UxmlStringAttributeDescription _bindingSelectedItemPath = new()
{ name = "binding-selected-item-path", defaultValue = "SelectedItem" };
public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context)
{
base.Init(visualElement, bag, context);
var control = (MyListView) visualElement;
control.BindingSelectedItemPath = _bindingSelectedItemPath.GetValueFromBag(bag, context);
}
}
} Finally, you can create a BindingContextProvider to provide the [UxmlElement]
public partial class MyItemViewModelProvider : BindingContextProvider<MyItemViewModel>
{
} And use everything as follows. <ui:UXML xmlns:uitk="UnityMvvmToolkit.UITK.BindableUIElements" ...>
<MyItemViewModelProvider binding-context-path="SelectedItem">
<uitk:BindableLabel binding-text-path="Name" />
</MyItemViewModelProvider>
<MyListView binding-items-source-path="Items" binding-selected-item-path="SelectedItem" />
</ui:UXML>
|
Beta Was this translation helpful? Give feedback.
-
Do I get it right that I'd have to write a separate view for each viewmodel type that I'd like to have this working with? Is there a way to reduce the amount of boilerplate and make it somewhat more generic? Ideally, one |
Beta Was this translation helpful? Give feedback.
There are two approaches, with and without the UnityMvvmToolkit.Generator.
Let's say we have the following ViewModels.
MyItemViewModel with UnityMvvmToolkit.Generator
MyItemViewModel without UnityMvvmToolkit.Generator