Skip to content

Commit 0145369

Browse files
authored
Merge pull request #37 from LibraStack/develop
New functionality and bug fixes.
2 parents d50d1f2 + a875635 commit 0145369

File tree

15 files changed

+556
-40
lines changed

15 files changed

+556
-40
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ The included UI elements are:
770770
- [BindableLabel](#bindablelabel)
771771
- [BindableTextField](#bindabletextfield)
772772
- [BindableButton](#bindablebutton)
773+
- [BindableDropdownField](#bindabledropdownfield)
773774
- [BindableListView](#bindablelistview)
774775
- [BindableScrollView](#bindablescrollview)
775776
- [BindingContextProvider](#bindingcontextprovider)
@@ -840,6 +841,37 @@ The `BindableButton` can be bound to the following commands:
840841

841842
To pass a parameter to the viewmodel, see the [ParameterValueConverter](#parametervalueconverterttargettype) section.
842843

844+
#### BindableDropdownField
845+
846+
The `BindableDropdownField` allows the user to pick a choice from a list of options. The `BindingSelectedItemPath` attribute is optional.
847+
848+
```csharp
849+
public class DropdownFieldViewModel : IBindingContext
850+
{
851+
public DropdownFieldViewModel()
852+
{
853+
var items = new ObservableCollection<string>
854+
{
855+
"Value 1",
856+
"Value 2",
857+
"Value 3"
858+
};
859+
860+
Items = new ReadOnlyProperty<ObservableCollection<string>>(items);
861+
SelectedItem = new Property<string>("Value 1");
862+
}
863+
864+
public IReadOnlyProperty<ObservableCollection<string>> Items { get; }
865+
public IProperty<string> SelectedItem { get; }
866+
}
867+
```
868+
869+
```xml
870+
<ui:UXML xmlns:uitk="UnityMvvmToolkit.UITK.BindableUIElements" ...>
871+
<uitk:BindableDropdownField binding-items-source-path="Items" binding-selected-item-path="SelectedItem" />
872+
</ui:UXML>
873+
```
874+
843875
#### BindableListView
844876

845877
The `BindableListView` control is the most efficient way to create lists. It uses virtualization and creates VisualElements only for visible items. Use the `binding-items-source-path` of the `BindableListView` to bind to an `ObservableCollection`.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityMvvmToolkit.Core.Interfaces;
4+
5+
namespace UnityMvvmToolkit.Common
6+
{
7+
public sealed class BindableElementData : IDisposable
8+
{
9+
private readonly List<IBindableElement> _bindableElements;
10+
11+
public BindableElementData(List<IBindableElement> bindableElements)
12+
{
13+
_bindableElements = bindableElements;
14+
}
15+
16+
public IBindingContext BindingContext { get; set; }
17+
public IReadOnlyList<IBindableElement> BindableElements => _bindableElements;
18+
19+
public void Dispose()
20+
{
21+
_bindableElements.Clear();
22+
BindingContext = default;
23+
}
24+
}
25+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/BindableElementData.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#if UNITYMVVMTOOLKIT_TEXTMESHPRO_SUPPORT
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Collections.ObjectModel;
6+
using System.Collections.Specialized;
7+
using System.Linq;
8+
using System.Runtime.CompilerServices;
9+
using TMPro;
10+
using UnityEngine;
11+
using UnityMvvmToolkit.Core;
12+
using UnityMvvmToolkit.Core.Extensions;
13+
using UnityMvvmToolkit.Core.Interfaces;
14+
15+
namespace UnityMvvmToolkit.UGUI.BindableUGUIElements
16+
{
17+
[RequireComponent(typeof(TMP_Dropdown))]
18+
public class BindableDropdown : MonoBehaviour, IBindableElement
19+
{
20+
[SerializeField] private TMP_Dropdown _dropdown;
21+
[SerializeField] private string _bindingSelectedItemPath;
22+
[SerializeField] private string _bindingItemsSourcePath;
23+
24+
private IProperty<string> _selectedItemProperty;
25+
private IReadOnlyProperty<ObservableCollection<string>> _itemsSource;
26+
27+
private PropertyBindingData _selectedItemBindingData;
28+
private PropertyBindingData _itemsSourceBindingData;
29+
30+
public void SetBindingContext(IBindingContext context, IObjectProvider objectProvider)
31+
{
32+
if (string.IsNullOrWhiteSpace(_bindingItemsSourcePath) == false)
33+
{
34+
_itemsSourceBindingData ??= _bindingItemsSourcePath.ToPropertyBindingData();
35+
_itemsSource = objectProvider
36+
.RentReadOnlyProperty<ObservableCollection<string>>(context, _itemsSourceBindingData);
37+
_itemsSource.Value.CollectionChanged += OnItemsCollectionChanged;
38+
_dropdown.options = new List<TMP_Dropdown.OptionData>(_itemsSource.Value.Select(value => new TMP_Dropdown.OptionData(value)));
39+
}
40+
41+
if (string.IsNullOrWhiteSpace(_bindingSelectedItemPath) == false)
42+
{
43+
_selectedItemBindingData ??= _bindingSelectedItemPath.ToPropertyBindingData();
44+
_selectedItemProperty = objectProvider.RentProperty<string>(context, _selectedItemBindingData);
45+
_selectedItemProperty.ValueChanged += OnPropertySelectedItemChanged;
46+
47+
var foundIndex = _dropdown.options.FindIndex(option => option.text == _selectedItemProperty.Value);
48+
if (foundIndex != -1)
49+
{
50+
UpdateControlValue(foundIndex);
51+
}
52+
53+
_dropdown.onValueChanged.AddListener(OnControlValueChanged);
54+
_selectedItemProperty.Value = _dropdown.options.Count > 0 ? _dropdown.options[0].text : default;
55+
}
56+
}
57+
58+
private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
59+
{
60+
if (e.Action == NotifyCollectionChangedAction.Add)
61+
{
62+
foreach (string newItem in e.NewItems)
63+
{
64+
_dropdown.options.Add(new TMP_Dropdown.OptionData(newItem));
65+
}
66+
}
67+
68+
if (e.Action == NotifyCollectionChangedAction.Remove)
69+
{
70+
foreach (string oldItem in e.OldItems)
71+
{
72+
_dropdown.options.Remove(new TMP_Dropdown.OptionData(oldItem));
73+
}
74+
}
75+
76+
if (e.Action == NotifyCollectionChangedAction.Reset)
77+
{
78+
_dropdown.options.Clear();
79+
}
80+
}
81+
82+
public virtual void ResetBindingContext(IObjectProvider objectProvider)
83+
{
84+
if (_itemsSource != null)
85+
{
86+
_itemsSource.Value.CollectionChanged -= OnItemsCollectionChanged;
87+
objectProvider.ReturnReadOnlyProperty(_itemsSource);
88+
_itemsSource = null;
89+
_dropdown.options = new List<TMP_Dropdown.OptionData>();
90+
}
91+
92+
if (_selectedItemProperty != null)
93+
{
94+
_selectedItemProperty.ValueChanged -= OnPropertySelectedItemChanged;
95+
objectProvider.ReturnProperty(_selectedItemProperty);
96+
_selectedItemProperty = null;
97+
_dropdown.onValueChanged.RemoveListener(OnControlValueChanged);
98+
}
99+
100+
UpdateControlValue(default);
101+
}
102+
103+
protected virtual void OnControlValueChanged(int index)
104+
{
105+
_selectedItemProperty.Value = _dropdown.options[index].text;
106+
}
107+
108+
private void OnPropertySelectedItemChanged(object sender, string newValue)
109+
{
110+
var foundIndex = _dropdown.options.FindIndex(option => option.text == newValue);
111+
if (foundIndex == -1)
112+
{
113+
return;
114+
}
115+
116+
UpdateControlValue(foundIndex);
117+
}
118+
119+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
120+
protected virtual void UpdateControlValue(int newValue)
121+
{
122+
_dropdown.SetValueWithoutNotify(newValue);
123+
}
124+
}
125+
}
126+
127+
#endif

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableButton.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public virtual void SetBindingContext(IBindingContext context, IObjectProvider o
3434

3535
public virtual void ResetBindingContext(IObjectProvider objectProvider)
3636
{
37-
if (_command == null)
37+
if (_command is null)
3838
{
3939
return;
4040
}

0 commit comments

Comments
 (0)