Как сделать привязки в ItemContainerStyle в WinRT?
Я пытаюсь привязать коллекцию к ItemsControl, с Canvas как панель элементов, и с каждым элементом Canvas.Left и Top привязаны к свойствам объектов объекта. В основном я пытаюсь воссоздать двухмерную привязку данных, описанную в этой записи в своем блоге, но на этот раз в WinRT вместо WPF.
Так как ItemsControl обертывает содержимое ItemTemplate в другом элементе пользовательского интерфейса (ContentPresenter, в случае с WinRT), и это те элементы оболочки/контейнера, которые размещаются непосредственно внутри панели элементов, слева и сверху должны быть установлены на те контейнеры; вы не можете просто установить их в DataTemplate. В WPF достаточно легко сделать это с привязками в ItemContainerStyle, например:
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding Path=X}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
Но когда я пытаюсь сделать то же самое в проекте WinRT/XAML, я ничего не получаю. Даже ошибки привязки. Если я жестко кодирую значение, он работает; но если я использую привязку, свойство просто остается по умолчанию (ноль), и в окне вывода не отображаются ошибки привязки.
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<!-- This works, so ItemContainerStyle does work in WinRT: -->
<Setter Property="Canvas.Left" Value="200"/>
<!-- But this silently fails, leaves Top as 0, and does not show
any binding errors in the debugger Output window: -->
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
Я проверил, что у ContentPresenters есть правильный DataContext (т.е. элемент коллекции, а не сама коллекция или что-то еще фанковое), поэтому вы считаете, что эти привязки будут работать нормально. Но они даже не оцениваются. Если я помещаю плохую привязку в другое место и запускаю сборку отладки, я вижу ошибки привязки в окне вывода отладчика; но если я ссылаюсь на бессмысленное свойство внутри моего ItemContainerStyle, никаких ошибок привязки не отображаются.
Вот более полный пример, который (насколько мне известно) должен работать нормально в WPF, но это оставляет все в начале в WinRT:
<ItemsControl ItemsSource="{Binding Tiles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding DataContext.Left}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="80" Height="80" Fill="Gray"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Я попробовал несколько более экзотических опций на Binding
- в частности RelativeSource
. Когда я использовал RelativeSource TemplatedParent
, поведение do-nothing не изменилось. Однако, когда я использовал RelativeSource Self
, я получил ошибку привязки, заявив, что свойство не существует в типе Setter
! Он принимает это Self
немного слишком буквально, там.
Я также играл с TemplateBinding
, но я никогда не искал то, что должно было использоваться, и все, что у меня было, это некоторые непонятные COM-ошибки (добро пожаловать в WinRT, огромный технологический шаг назад).
Как я могу (a) правильно настроить привязки (есть ли другие опции в Binding
, которые я мог бы использовать, чтобы заставить его работать правильно?) или (b) в противном случае разрешить элементы в моем ItemsContainer
произвольно размещаться на Canvas
на основе привязки данных к свойствам элементов коллекции?
Ответы
Ответ 1
Привязки не поддерживаются в Setters. Я думаю, что Silverlight получил их только в версии 5, если вообще. Для обходных путей вы можете посмотреть мою более старую статью здесь. В основном вы определяете прикрепленное свойство зависимостей, которое устанавливает привязку для вас.
Ответ 2
Применение RenderTransform, похоже, хорошо работает для меня в silverlight и winrt/metro/8.1:
<ItemsControl ItemsSource="{Binding TreeMapItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="{Binding Brush}" ToolTipService.ToolTip="{Binding Label}">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding X}" Y="{Binding Y}"/>
</Rectangle.RenderTransform>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Ответ 3
Альтернативы: здесь есть другие возможности прикреплять привязки через код во время создания "Item" перед представлением.
ItemsControl.PrepareContainerForItemOverride
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.ui.xaml.controls.itemscontrol.preparecontainerforitemoverride.aspx
ListViewBase.ContainerContentChanging
http://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.ui.xaml.controls.listviewbase.containercontentchanging.aspx