diff --git a/README.md b/README.md
index ac16635..dad7b2f 100644
--- a/README.md
+++ b/README.md
@@ -840,6 +840,44 @@ The `BindableButton` can be bound to the following commands:
To pass a parameter to the viewmodel, see the [ParameterValueConverter](#parametervalueconverterttargettype) section.
+#### BindableDropdownField
+
+The `BindableDropdownField` allows you to work with dropdown. To set the binding of the selected value, you need to write `binding-selected-item-path`, and to set the binding of all dropdown elements, you need to use `binding-items-source-path`.
+Moreover, you can set them independently of each other.
+
+The following example demonstrates how to bind to a collection of strings with `BindableDropdownField`.
+
+In XML, you need to write the following:
+
+```xml
+
+
+
+```
+And in the C# class the following:
+
+```csharp
+public class DropdownFieldViewModel : IBindingContext
+{
+ public DropdownFieldViewModel()
+ {
+ TextValues = new ReadOnlyProperty>(new ObservableCollection()
+ {
+ "Value1",
+ "Value2",
+ "Value3"
+ });
+
+ SelectedValue = new Property();
+ SelectedValue.Value = "Value1";
+ }
+
+ public IProperty SelectedValue { get; }
+
+ public IReadOnlyProperty> Choices { get; }
+}
+```
+
#### BindableListView
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`.
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs
new file mode 100644
index 0000000..3f0da78
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs
@@ -0,0 +1,127 @@
+#if UNITYMVVMTOOLKIT_TEXTMESHPRO_SUPPORT
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using TMPro;
+using UnityEngine;
+using UnityMvvmToolkit.Core;
+using UnityMvvmToolkit.Core.Extensions;
+using UnityMvvmToolkit.Core.Interfaces;
+
+namespace UnityMvvmToolkit.UGUI.BindableUGUIElements
+{
+ [RequireComponent(typeof(TMP_Dropdown))]
+ public class BindableDropdown : MonoBehaviour, IBindableElement
+ {
+ [SerializeField] private TMP_Dropdown _dropdown;
+ [SerializeField] private string _bindingSelectedItemPath;
+ [SerializeField] private string _bindingItemsSourcePath;
+
+ private IProperty _selectedItemProperty;
+ private IReadOnlyProperty> _itemsSource;
+
+ private PropertyBindingData _selectedItemBindingData;
+ private PropertyBindingData _itemsSourceBindingData;
+
+ public void SetBindingContext(IBindingContext context, IObjectProvider objectProvider)
+ {
+ if (string.IsNullOrWhiteSpace(_bindingItemsSourcePath) == false)
+ {
+ _itemsSourceBindingData ??= _bindingItemsSourcePath.ToPropertyBindingData();
+ _itemsSource = objectProvider
+ .RentReadOnlyProperty>(context, _itemsSourceBindingData);
+ _itemsSource.Value.CollectionChanged += OnItemsCollectionChanged;
+ _dropdown.options = new List(_itemsSource.Value.Select(value => new TMP_Dropdown.OptionData(value)));
+ }
+
+ if (string.IsNullOrWhiteSpace(_bindingSelectedItemPath) == false)
+ {
+ _selectedItemBindingData ??= _bindingSelectedItemPath.ToPropertyBindingData();
+ _selectedItemProperty = objectProvider.RentProperty(context, _selectedItemBindingData);
+ _selectedItemProperty.ValueChanged += OnPropertySelectedItemChanged;
+
+ var foundIndex = _dropdown.options.FindIndex(option => option.text == _selectedItemProperty.Value);
+ if (foundIndex != -1)
+ {
+ UpdateControlValue(foundIndex);
+ }
+
+ _dropdown.onValueChanged.AddListener(OnControlValueChanged);
+ _selectedItemProperty.Value = _dropdown.options.Count > 0 ? _dropdown.options[0].text : default;
+ }
+ }
+
+ private void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action == NotifyCollectionChangedAction.Add)
+ {
+ foreach (string newItem in e.NewItems)
+ {
+ _dropdown.options.Add(new TMP_Dropdown.OptionData(newItem));
+ }
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Remove)
+ {
+ foreach (string oldItem in e.OldItems)
+ {
+ _dropdown.options.Remove(new TMP_Dropdown.OptionData(oldItem));
+ }
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ _dropdown.options.Clear();
+ }
+ }
+
+ public virtual void ResetBindingContext(IObjectProvider objectProvider)
+ {
+ if (_itemsSource != null)
+ {
+ _itemsSource.Value.CollectionChanged -= OnItemsCollectionChanged;
+ objectProvider.ReturnReadOnlyProperty(_itemsSource);
+ _itemsSource = null;
+ _dropdown.options = new List();
+ }
+
+ if (_selectedItemProperty != null)
+ {
+ _selectedItemProperty.ValueChanged -= OnPropertySelectedItemChanged;
+ objectProvider.ReturnProperty(_selectedItemProperty);
+ _selectedItemProperty = null;
+ _dropdown.onValueChanged.RemoveListener(OnControlValueChanged);
+ }
+
+ UpdateControlValue(default);
+ }
+
+ protected virtual void OnControlValueChanged(int index)
+ {
+ _selectedItemProperty.Value = _dropdown.options[index].text;
+ }
+
+ private void OnPropertySelectedItemChanged(object sender, string newValue)
+ {
+ var foundIndex = _dropdown.options.FindIndex(option => option.text == newValue);
+ if (foundIndex == -1)
+ {
+ return;
+ }
+
+ UpdateControlValue(foundIndex);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected virtual void UpdateControlValue(int newValue)
+ {
+ _dropdown.SetValueWithoutNotify(newValue);
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs.meta
new file mode 100644
index 0000000..05c1cb9
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UGUI/BindableUGUIElements/BindableDropdown.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f7044586e66117e48948637bf2c66eaa
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs
new file mode 100644
index 0000000..cb05421
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using UnityEngine.UIElements;
+using UnityMvvmToolkit.Common.Interfaces;
+using UnityMvvmToolkit.Core;
+using UnityMvvmToolkit.Core.Extensions;
+using UnityMvvmToolkit.Core.Interfaces;
+
+namespace UnityMvvmToolkit.UITK.BindableUIElements
+{
+ public partial class BindableDropdownField : DropdownField, IBindableCollection, IInitializable, IDisposable
+ {
+ private IProperty _selectedItemProperty;
+ private IReadOnlyProperty> _itemsSource;
+
+ private PropertyBindingData _selectedItemBindingData;
+ private PropertyBindingData _itemsSourceBindingData;
+
+ public void Initialize()
+ {
+ choices = new List();
+ }
+
+ public void Dispose()
+ {
+ choices.Clear();
+ }
+
+ public void SetBindingContext(IBindingContext context, IObjectProvider objectProvider)
+ {
+ if (string.IsNullOrWhiteSpace(BindingItemsSourcePath) == false)
+ {
+ _itemsSourceBindingData ??= BindingItemsSourcePath.ToPropertyBindingData();
+ _itemsSource = objectProvider
+ .RentReadOnlyProperty>(context, _itemsSourceBindingData);
+ _itemsSource.Value.CollectionChanged += OnItemsCollectionChanged;
+ choices = new List(_itemsSource.Value);
+ }
+
+ if (string.IsNullOrWhiteSpace(BindingSelectedItemPath) == false)
+ {
+ _selectedItemBindingData ??= BindingSelectedItemPath.ToPropertyBindingData();
+ _selectedItemProperty = objectProvider.RentProperty(context, _selectedItemBindingData);
+ _selectedItemProperty.ValueChanged += OnSelectedItemValueChanged;
+
+ var isContains = choices.Contains(_selectedItemProperty.Value);
+ if (isContains == true)
+ {
+ UpdateControlValue(_selectedItemProperty.Value);
+ }
+
+ this.RegisterValueChangedCallback(OnControlValueChanged);
+ _selectedItemProperty.Value = choices.Count > 0 ? choices[0] : default;
+ }
+ }
+
+ protected virtual void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action == NotifyCollectionChangedAction.Add)
+ {
+ foreach (string newItem in e.NewItems)
+ {
+ choices.Add(newItem);
+ }
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Remove)
+ {
+ foreach (string oldItem in e.OldItems)
+ {
+ choices.Remove(oldItem);
+ }
+ }
+
+ if (e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ choices.Clear();
+ }
+ }
+
+ public virtual void ResetBindingContext(IObjectProvider objectProvider)
+ {
+ if (_selectedItemProperty != null)
+ {
+ _selectedItemProperty.ValueChanged -= OnSelectedItemValueChanged;
+ objectProvider.ReturnProperty(_selectedItemProperty);
+ _selectedItemProperty = null;
+ this.UnregisterValueChangedCallback(OnControlValueChanged);
+ }
+
+ if (_itemsSource != null)
+ {
+ _itemsSource.Value.CollectionChanged -= OnItemsCollectionChanged;
+ choices = new List();
+ objectProvider.ReturnReadOnlyProperty(_itemsSource);
+ _itemsSource = null;
+ }
+
+ UpdateControlValue(default);
+ }
+
+ protected virtual void OnControlValueChanged(ChangeEvent e)
+ {
+ _selectedItemProperty.Value = e.newValue;
+ }
+
+ private void OnSelectedItemValueChanged(object sender, string newValue)
+ {
+ var isContains = choices.Contains(newValue);
+ if (isContains == false)
+ {
+ return;
+ }
+
+ UpdateControlValue(newValue);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected virtual void UpdateControlValue(string newValue)
+ {
+ SetValueWithoutNotify(newValue);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs.meta
new file mode 100644
index 0000000..065981e
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/BindableDropdownField.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8c46923c0a364c539ce1f2895dec04ed
+timeCreated: 1686411067
\ No newline at end of file
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs
new file mode 100644
index 0000000..f89007b
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs
@@ -0,0 +1,57 @@
+using UnityEngine.UIElements;
+using UnityMvvmToolkit.UITK.Extensions;
+
+namespace UnityMvvmToolkit.UITK.BindableUIElements
+{
+ partial class BindableDropdownField
+ {
+ public string BindingSelectedItemPath { get; private set; }
+
+ public string BindingItemsSourcePath { get; private set; }
+
+ public new class UxmlFactory : UxmlFactory
+ {
+ }
+
+#if UNITY_2023_2_OR_NEWER
+ [System.Serializable]
+ public new class UxmlSerializedData : DropdownField.UxmlSerializedData
+ {
+ // ReSharper disable once InconsistentNaming
+ #pragma warning disable 649
+ [UnityEngine.SerializeField] private string BindingSelectedItemPath;
+ [UnityEngine.SerializeField] private string BindingItemsSourcePath;
+ #pragma warning restore 649
+
+ public override object CreateInstance() => new BindableDropdownField();
+ public override void Deserialize(object visualElement)
+ {
+ base.Deserialize(visualElement);
+
+ var bindableDropdownField = visualElement.As();
+ bindableDropdownField.BindingSelectedItemPath = BindingSelectedItemPath;
+ bindableDropdownField.BindingItemsSourcePath = BindingItemsSourcePath;
+ }
+ }
+#else
+ public new class UxmlTraits : DropdownField.UxmlTraits
+ {
+ private readonly UxmlStringAttributeDescription _bindingSelectedItemPath = new()
+ { name = "binding-selected-item-path", defaultValue = "" };
+
+ private readonly UxmlStringAttributeDescription _bindingItemsSourcePath = new()
+ { name = "binding-items-source-path", defaultValue = "" };
+
+ public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context)
+ {
+ base.Init(visualElement, bag, context);
+
+ var bindableDropdownField = visualElement.As();
+
+ bindableDropdownField.BindingSelectedItemPath = _bindingSelectedItemPath.GetValueFromBag(bag, context);
+ bindableDropdownField.BindingItemsSourcePath = _bindingItemsSourcePath.GetValueFromBag(bag, context);
+ }
+ }
+#endif
+ }
+}
\ No newline at end of file
diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs.meta
new file mode 100644
index 0000000..32d3949
--- /dev/null
+++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UITK/BindableUIElements/Uxmls/BindableDropdownField.Uxml.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6c58f7387a96411e88df2f3f4963bb93
+timeCreated: 1686411216
\ No newline at end of file