none
Для чего нужно <DataTrigger Binding> в <DataTemplate.Triggers> ? RRS feed

  • Вопрос

  • Сейчас разбираю шаблон MVVM на примере приложения приложения Джоша Смита

    http://msdn.microsoft.com/ru-ru/magazine/dd419663.aspx

    Работаю с исходниками этого приложения. Там в проекте DemoApp есть, в частности, файл AllCustomersView.xaml и в нем присутствует следующая конструкция в XAML:

        <GroupStyle x:Key="CustomerGroupStyle">
          <GroupStyle.HeaderTemplate>
            <DataTemplate>
              <TextBlock 
                x:Name="txt" 
                Background="{StaticResource Brush_HeaderBackground}"
                FontWeight="Bold"
                Foreground="White"
                Margin="1"
                Padding="4,2,0,2"
                Text="People" 
                />
              <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=Name}" Value="True">
                  <Setter TargetName="txt" Property="Text" Value="Companies" />
                </DataTrigger>
              </DataTemplate.Triggers>
            </DataTemplate>
          </GroupStyle.HeaderTemplate>
        </GroupStyle>

    Мне в ней непонятны следующие строки:

    <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=Name}" Value="True">
                     <Setter TargetName="txt" Property="Text" Value="Companies" />
            </DataTrigger>
    </DataTemplate.Triggers>

    Пробовал разобраться через MSDN, но там, на мой взгляд, DataTrigger Binding описано немного туманно (просто раньше не сталкивался, а тут налетел). Ребята, скажите (напишите), пожалуйста кто-нибудь по русски - что обозначают эти вышеприведённые строки XAML о DataTrigger Binding?


Ответы

  • DataTemplate это шаблон данных. DataTemplate.Triggers это триггеры шаблона данных.

    Триггеры это такие действия которые срабатывают только при указанных условиях. Условие выполнилось - триггер сработал, перестало выполнятся все вернулось в исходную.

    DataTrigger это один из вариантов триггеров, который поддерживает привязку к данным (бывают еще зависящие от свойств и от событий). Соответственно в указанном вами примере триггер сработает когда свойство Name в объекте данных будет True.

    Ну а Setter выполняет само действие. В данном случае элементу шаблона с именем txt в свойство Text устанавливается значение Companies. Еще раз обращу внимание на то что это будет действовать пока пока триггер выполняется. Как только Name станет False txt.Text вернется в прежнее значение.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Предложено в качестве ответа Taras KovalenkoBanned 2 мая 2013 г. 6:58
    • Помечено в качестве ответа TownSparrow 3 мая 2013 г. 7:41
    Отвечающий

Все ответы

  • DataTemplate это шаблон данных. DataTemplate.Triggers это триггеры шаблона данных.

    Триггеры это такие действия которые срабатывают только при указанных условиях. Условие выполнилось - триггер сработал, перестало выполнятся все вернулось в исходную.

    DataTrigger это один из вариантов триггеров, который поддерживает привязку к данным (бывают еще зависящие от свойств и от событий). Соответственно в указанном вами примере триггер сработает когда свойство Name в объекте данных будет True.

    Ну а Setter выполняет само действие. В данном случае элементу шаблона с именем txt в свойство Text устанавливается значение Companies. Еще раз обращу внимание на то что это будет действовать пока пока триггер выполняется. Как только Name станет False txt.Text вернется в прежнее значение.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    • Предложено в качестве ответа Taras KovalenkoBanned 2 мая 2013 г. 6:58
    • Помечено в качестве ответа TownSparrow 3 мая 2013 г. 7:41
    Отвечающий
  • Спасибо. Пользуясь случаем хочу спросить - вот вы пишите, что триггеры (бывают еще зависящие от свойств и от событий), тогда триггеры вида DataTrigger можно назвать зависящими от значения источника привязки?

    P.S.  Если мне в форуме помогут, то чуствую, что получу зацепку и с помощью форума и MSDN раскопаю всё что мне нужно.



  • Пользуясь случаем хочу спросить - вот вы пишите, что триггеры (бывают еще зависящие от свойств и от событий), тогда триггеры вида DataTrigger можно назвать зависящими от значения источника привязки?

    Да. Хотя сказать "зависящие от" может не совсем верно. Скорее они позволяют создавать действия при:

    1. Возникновение события. В таких триггерах чаще всего запускают анимацию.

    2. Установке некого свойства текущего объекта. Например можно сделать Button.Triggers и следить пока кнопка не станет IsEnabled=False, что бы что то с ней сделать. Например поменять текст внутри.

    3. От свойств объекта данных. Случай из данной темы. Если вам нужно отреагировать на изменение свойства из объекта данных, то нужен DataTrigger.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    Отвечающий
  • <UserControl x:Class="DemoApp.View.AllCustomersView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"> <UserControl.Resources> <!--Определить представление для коллекции покупателей--> <CollectionViewSource x:Key="CustomerGroups" Source="{Binding Path=AllCustomers}"> <!--Установить внутри представления группировку элементов по субъекту права покупателя. Свойство IsCompany - булевое. Оно равно true, если покупатель - юр.лицо. Т.е. здесь мы как бы разбиваем представление на две группы: 1) покупатели юр.лица и 2) покупатели физ.лица--> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="IsCompany" /> </CollectionViewSource.GroupDescriptions> <CollectionViewSource.SortDescriptions> <!--Отсортировать элементы в CustomerGroups так, чтобы сначала шли юридические лица, а затем - физические. Т.е. те элементы, у которых IsCompany == true будут (в порядке сортировки) иметь большее значение, чем те, у которых IsCompany == false--> <scm:SortDescription PropertyName="IsCompany" Direction="Descending" /> <!--Внутри же групп сортировать по алфавиту по возрастанию.--> <scm:SortDescription PropertyName="DisplayName" Direction="Ascending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> <!--Определить вид группы в окне--> <GroupStyle x:Key="CustomerGroupStyle"> <!--Определить шаблон для показа заголовка группы--> <GroupStyle.HeaderTemplate> <!--Описать визуальную структуру заголовка группы как текстовый блок с указанным цветом фона, с жирным шрифтом, с белым цветом шрифта, с указанными внешней и внутренней границами своей области и текстом "People" по умолчанию--> <DataTemplate> <TextBlock x:Name="txt" Background="{StaticResource Brush_HeaderBackground}" FontWeight="Bold" Foreground="White" Margin="1" Padding="4,2,0,2" Text="People" /> <!--Триггер установит заголовок группы в "Companies", если значение свойства Name будет равно true. (Но откуда, блин, оно взялось это с-во Name? В View Model'ах примера Смита такого свойства нет...)--> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Path=Name}" Value="True"> <Setter TargetName="txt" Property="Text" Value="Companies" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </GroupStyle.HeaderTemplate> </GroupStyle>

    . . . . . . . . . . . . . . . . . . . . . . . . . . .

     Выше привожу немного больше XAML-кода по моему вопросу. (Комментарии в нём - мои).

    В основном понятно. Но вот свойство Name в строках:

    <DataTrigger Binding="{Binding Path=Name}" Value="True">
               <Setter TargetName="txt" Property="Text" Value="Companies" />
    </DataTrigger>

    Откуда оно, Бог его знает, взялось? Ведь в моделях представления (View Models) которые Смит описывает в примере приложения этого свойства (именно с именем Name) нет в помине (хотя на всякий случай ещё проверю). Может быть оно каким-либо образом выводится именно здесь из контекста этой разметки XAML? Вот откуда оно взялось?




  • Вы забыли о том, что триггер находится в DataTemplate, а DataTemplate это шаблон представления некого объекта данных. Например в ListBox отображается ряд классов с полями Name, Content и Image. Соответственно Binding Path=Name это привязка к одному из свойств текущего объекта.

    Вот у вас UserControl помимо прочего имеющий заголовок группы. То есть коллекция AllCustomers представляет из себя некие классы в которых есть поле заголовка группы и поле списков ее элементов. Так вот в вашем случае Binding Path=Name это привязка именно к полю заголовка группы. То есть к полю Name того класса из которого формируется коллекция AllCustomers. Если в этом классе нет такого поля, то вы его видимо убрали посчитав не важным.


    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    Отвечающий
  • В том-то и дело, что его там не было. Следовательно и убрать я его не мог. Вряд ли и сам Смит мог ошибиться. Может переводчик статьи?... Но вряд ли он трогал исходники, ведь приложение-то компилируется, запускается и работает нормально. А свойства Name в нём вобще нет. Нет его соответственно и в классе, которым представлены элементы коллекции AllCustomers. Вот в чём гвоздь.

    P.S. Сейчас ещё раз почитаю саму его статью.