3.5.1.4. Использование фрагментов экранов
В данном разделе рассматриваются примеры определения и использования фрагментов экранов. См. также раздел События ScreenFragment для получения информации о событиях жизненного цикла фрагментов.
- Декларативное использование фрагмента
-
Предположим, имеется фрагмент для ввода адреса:
AddressFragment.java@UiController("demo_AddressFragment") @UiDescriptor("address-fragment.xml") public class AddressFragment extends ScreenFragment { }
address-fragment.xml<fragment xmlns="http://schemas.haulmont.com/cuba/screen/fragment.xsd"> <layout> <textField id="cityField" caption="City"/> <textField id="zipField" caption="Zip"/> </layout> </fragment>
Он может быть включен в некоторый экран с помощью элемента
fragment
с атрибутомscreen
, указывающим на id фрагмента, который задан в аннотации@UiController
:host-screen.xml<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="Some Screen"> <layout> <groupBox id="addressBox" caption="Address"> <fragment screen="demo_AddressFragment"/> </groupBox> </layout> </window>
Элемент
fragment
может быть добавлен в любой UI-контейнер экрана, в том числе в корневой элементlayout
.
- Программное использование фрагмента
-
Тот же самый фрагмент может быть включен в экран программно в обработчике InitEvent или AfterInitEvent как показано ниже:
host-screen.xml<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="Some Screen"> <layout> <groupBox id="addressBox" caption="Address"/> </layout> </window>
HostScreen.java@UiController("demo_HostScreen") @UiDescriptor("host-screen.xml") public class HostScreen extends Screen { @Inject private Fragments fragments; (1) @Inject private GroupBoxLayout addressBox; @Subscribe private void onInit(InitEvent event) { AddressFragment addressFragment = fragments.create(this, AddressFragment.class); (2) addressBox.add(addressFragment.getFragment()); (3) } }
1 - инжекция бина Fragments
, который предназначен для инстанциирования фрагментов2 - создание экземпляра контроллера фрагмента по его классу 3 - получение визуального компонента Fragment
из контроллера и добавление его в UI-контейнерЕсли фрагменту нужны какие-либо параметры, установите их через публичные сеттеры перед добавлением фрагмента в экран. Тогда параметры будут доступны в обработчиках событий
InitEvent
иAfterInitEvent
контроллера фрагмента.
- Передача параметров в фрагменты
-
Контроллер фрагмента может иметь публичные сеттеры для получения параметров, как это делается при открытии экранов. Если фрагмент открывается программно, то сеттеры можно вызвать явно:
@UiController("demo_HostScreen") @UiDescriptor("host-screen.xml") public class HostScreen extends Screen { @Inject private Fragments fragments; @Inject private GroupBoxLayout addressBox; @Subscribe private void onInit(InitEvent event) { AddressFragment addressFragment = fragments.create(this, AddressFragment.class); addressFragment.setStrParam("some value"); (1) addressBox.add(addressFragment.getFragment()); } }
1 - передача параметра перед добавлением фрагмента в экран. Если фрагмент добавляется в экран декларативно в XML, для передачи параметров можно использовать элемент
properties
, например:<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="Some Screen"> <data> <instance id="someDc" class="com.company.demo.entity.Demo"/> </data> <layout> <textField id="someField"/> <fragment screen="demo_AddressFragment"> <properties> <property name="strParam" value="some value"/> (1) <property name="dataContainerParam" ref="someDc"/> (2) <property name="componentParam" ref="someField"/> (3) </properties> </fragment> </layout> </window>
1 - передача строкового параметра в метод setStrParam()
.2 - передача контейнера данных в метод setDataContainerParam()
.3 - передача компонента TextField
в методsetComponentParam()
.Атрибут
value
используется для указания значений, атрибутref
- для указания идентификаторов компонентов экрана. Сеттеры должны иметь параметры подходящего типа.
- Компоненты данных в фрагментах
-
Фрагмент экрана может иметь свои собственные контейнеры и загрузчики данных, определенные в XML-элементе
data
. В то же время, фреймворк создает единственный экземпляр DataContext для экрана и всех его фрагментов. Поэтому все загруженные сущности помещаются в один контекст и их изменения сохраняются, когда экран выполняет коммит.Далее рассматривается пример использования собственных компонентов данных в фрагменте.
Предположим, имеется сущность
City
, и во фрагменте вместо текстового поля необходимо отобразить выпадающий список с имеющимися городами. Во фрагменте можно определить компоненты данных точно так же, как в обычном экране:address-fragment.xml<fragment xmlns="http://schemas.haulmont.com/cuba/screen/fragment.xsd"> <data> <collection id="citiesDc" class="com.company.demo.entity.City" view="_base"> <loader id="citiesLd"> <query><![CDATA[select e from demo_City e ]]></query> </loader> </collection> </data> <layout> <lookupField id="cityField" caption="City" optionsContainer="citiesDc"/> <textField id="zipField" caption="Zip"/> </layout> </fragment>
Для того, чтобы загрузить данные в момент открытия включающего экрана, необходимо подписаться на событие экрана:
AddressFragment.java@UiController("demo_AddressFragment") @UiDescriptor("address-fragment.xml") public class AddressFragment extends ScreenFragment { @Inject private CollectionLoader<City> citiesLd; @Subscribe(target = Target.PARENT_CONTROLLER) (1) private void onBeforeShowHost(Screen.BeforeShowEvent event) { citiesLd.load(); } }
1 - подписка на BeforeShowEvent включающего экрана Аннотация
@LoadDataBeforeShow
в фрагментах экранов не действует.
- Контейнеры данных, предоставляемые экраном
-
Следующий пример демонстрирует использование контейнеров данных, предоставляемых включающим экраном.
host-screen.xml<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="Some Screen"> <data> <instance id="addressDc" class="com.company.demo.entity.Address"/> (1) </data> <layout> <groupBox id="addressBox" caption="Address"> <fragment screen="demo_AddressFragment"/> </groupBox> </layout> </window>
1 - контейнер данных, который используется фрагментом ниже address-fragment.xml<fragment xmlns="http://schemas.haulmont.com/cuba/screen/fragment.xsd"> <data> <instance id="addressDc" class="com.company.demo.entity.Address" provided="true"/> (1) <collection id="citiesDc" class="com.company.demo.entity.City" view="_base"> <loader id="citiesLd"> <query><![CDATA[select e from demo_City e]]></query> </loader> </collection> </data> <layout> <lookupField id="cityField" caption="City" optionsContainer="citiesDc" dataContainer="addressDc" property="city"/> (2) <textField id="zipField" caption="Zip" dataContainer="addressDc" property="zip"/> </layout> </fragment>
1 - provided="true"
означает, что контейнер с таким же id должен существовать во включающем экране или фрагменте, т.е. должен быть предоставлен извне2 - UI-компоненты соединены с предоставленным контейнером данных В XML-элементе, имеющем
provided="true"
, все атрибуты за исключениемid
игнорируются, но могут присутствовать для обеспечения работы инструментов разработки.