Как сделать привязки в ItemContainerStyle в WinRT?

Я пытаюсь привязать коллекцию к ItemsControl, используя Canvas в качестве панели элементов и привязывая свойства Canvas.Left и Top каждого элемента к объектам элемента. В основном я пытаюсь воссоздать двумерную привязку данных, которую я описал в этом посте в своем блоге, но на этот раз в WinRT вместо WPF.

Так как ItemsControl оборачивает содержимое ItemTemplate в другой элемент пользовательского интерфейса (ContentPresenter, в случае WinRT), и это те элементы-оболочки / контейнеры, которые размещаются непосредственно внутри панели элементов, в этих контейнерах должны быть установлены Left и Top; вы не можете просто установить их в 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's 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поведение бездействия не изменилось. Тем не менее, когда я использовал RelativeSource SelfЯ получил ошибку привязки, говоря, что свойство не существует по типу Setter! Это берет, что Self слишком буквально, там.

Я также играл с TemplateBinding, но я никогда не задумывался над тем, для чего он должен использоваться, и все, что я получил, это некоторые непонятные ошибки COM (добро пожаловать в WinRT, огромный технологический шаг назад).

Как я могу (а) заставить привязки работать правильно (есть ли другие варианты на Binding что я мог бы использовать, чтобы заставить его работать должным образом?), или (б) иначе разрешить элементы в моем ItemsContainer быть произвольно расположенным на Canvas на основе привязок данных к свойствам элементов коллекции?

3 ответа

Решение

Привязки не поддерживаются сеттерами. Я думаю, что Silverlight получил их только в версии 5, если вообще. В качестве обходного пути вы можете посмотреть мою старую статью здесь. По сути, вы определяете вложенное свойство зависимостей, которое устанавливает привязку для вас.

Мне кажется, что применение 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>

Альтернативы: здесь есть другие возможности прикрепить привязки через код во время создания "Предмета" перед презентацией.

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

Другие вопросы по тегам