Skip to content

ui::TwoWayField

Header: winui/core/Property.hpp.

template <typename T> class TwoWayField

Derives from ui::Binding< T >.

The type of an editable spec field: one the user changes and a two-way bind() writes back from (a text box's text, a slider's value, a selected_index, an is_open). It is a Binding in every way but two, both refusing a two-way bind() of a property that cannot hold what the control writes back, where a plain Binding would silently go one-way:

  • A writable Property<U> whose type loses some of the field's values does not compile: .value = level with a Property<int> level on a Slider, whose value is a double. Bind a property of the field's own type, or say one-way with bind_one_way(). Types that convert both ways without loss stay two-way (a Property<float> on that same Slider).
  • A field that can be unset (a selection that can be empty, a check box's indeterminate state, an empty number box) is a TwoWayField<std::optional<T>>, and a two-way bind() of a Property<T> into it does not compile: the control can go unset, which the property cannot hold. Bind a Property<std::optional<T>>, or bind_one_way().

A display field stays a plain Binding, and bind() of any property that converts goes into it one-way.

Example:

ui::Property<std::optional<std::size_t>> picked;
ui::Property<std::size_t>                size{0};
ui::Property<int>                        volume{40};
ui::ComboBox{.items = {"Small", "Large"}, .selected_index = picked};       // two-way
ui::ComboBox{.items = {"Small", "Large"}, .selected_index = ui::bind_one_way(size)}; // one-way
ui::Slider{.value = ui::bind_one_way(volume)};                             // one-way
// .selected_index = size does not compile: the dropdown can be left with
// nothing selected, which `size` cannot hold.
// .value = volume does not compile: a drag to 40.5 does not fit an int.

TwoWayField

TwoWayField() = default

A constant value-initialized T.

TwoWayField

TwoWayField(Binding<T> binding)

Any binding of the field's own type: a constant, bind() or bind_one_way().

TwoWayField

TwoWayField(ChoiceBinding choice)
    requires std::same_as<T, std::size_t>

bind_choice() into an index field that always shows a selection. A value not in the list leaves the selection where it is, and starts the field on the first choice.

TwoWayField

template <typename U>
TwoWayField(const TwoWayBinding<U>& two_way)
    requires detail::LossyWriteBack<U, T> && (!detail::UnsetIntoPlain<U, T>)

Does not compile: a two-way bind() of a Property<U> that cannot hold every value of the field. See the class comment.

TwoWayField

template <typename S>
TwoWayField(S& source)
    requires detail::is_source<S> && (!std::is_const_v<S>) && std::same_as<S, Property<detail::source_value_t<S>>> && detail::LossyWriteBack<detail::source_value_t<S>, T> && (!detail::UnsetIntoPlain<detail::source_value_t<S>, T>)

Does not compile: a writable Property<U> written straight into the field, the same two-way bind() as above. See the class comment.

TwoWayField

template <typename U>
TwoWayField(const TwoWayBinding<U>& two_way) = delete
    requires detail::OptionalValue<T>::optional && (!detail::OptionalValue<U>::optional)

Deleted: a two-way bind() of a Property<U> into a field that can be unset. See the class comment.

TwoWayField

template <typename S>
TwoWayField(S& source) = delete
    requires detail::is_source<S> && detail::PropertyBindsTo<detail::source_value_t<S>, T> && (!std::is_const_v<S>) && std::same_as<S, Property<detail::source_value_t<S>>> && detail::OptionalValue<T>::optional && (!detail::OptionalValue<detail::source_value_t<S>>::optional)

Deleted: a writable Property<U> written straight into a field that can be unset, which is the same two-way bind() as above. See the class comment.