Когда для ItemsControl ItemsControl.ItemsPanel установлено значение Canvas, появляется ContenPresenter и нарушает мои свойства Canvas для дочерних элементов [WPF]

Я использую ItemsControl, где ItemsPanel установлен на Canvas (см. этот вопрос для получения дополнительной справочной информации). ItemsControl работает так, как я хочу, и он работает как шарм при добавлении дочернего элемента вручную, помещая его в ItemsControl.Items:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Items>
        <Button Canvas.Left="500" Content="Button Text" />
    </ItemsControl.Items>
</ItemsControl>

Обратите внимание на свойство Canvas.Left на кнопке. Это работает как чудо, и кнопка помещается на 500 пикселей слева от левой стороны ItemsControl. Здорово!

Однако, когда я определяю привязку ItemsSource к списку, Canvas.left не имеет никакого эффекта:

<ItemsControl ItemsSource="{Binding Elements}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Canvas.Left="500" Content="Button Text" />
        </DataTemplate>     
    </ItemsControl.ItemTemplate>
</ItemsControl> 

Изучая приложение во время выполнения, я вижу одно отличие. Контейнер ContentPresenter был добавлен между холстом и кнопкой ..

Как установить свойство Canvas.Left в самом ContentPresenter? Или есть другой способ решить эту проблему?

Спасибо всем!


person code-zoop    schedule 10.03.2010    source источник


Ответы (3)


На ум приходят несколько решений:

  1. используйте layout / rendertransform вместо прикрепленного свойства
  2. использовать маржу вместо прикрепленного свойства
  3. являются производными от ItemsControl и переопределяют поведение при создании дочерних контейнеров. (GetContainerForItemOverride, IsItemItsOwnContainerOverride). Эта статья прекрасно объясняет, как это работает: http://drwpf.com/blog/2008/07/20/itemscontrol-g-is-for-generator/
person Martin Moser    schedule 10.03.2010

Можно установить свойство Canvas.Left с помощью ItemContainerStyle:

<ItemsControl ItemsSource="{Binding Elements}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Content="Button Text" />
            </DataTemplate>     
        </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style>
             <Setter Property="Canvas.Left" Value="500" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>
person LiamV    schedule 09.05.2010
comment
Вы также можете привязать значение в ItemContainerStyle, и оно будет использовать тот же элемент, что и DataTemplate, который используется в качестве источника. :-) - person Russell Giddings; 20.06.2013
comment
Ты мой герой сегодня. Спасибо. - person Peter pete; 26.08.2014

Button не имеет свойства Canvas, поэтому вы делаете относительный вызов элемента управления хостингом, однако, поскольку элемент и холст находятся в разных шаблонах, прямой ссылки нет, из-за этого Canvas.Left бессмысленно до времени выполнения.

следовательно, ваш метод не может найти левую часть для установки, поэтому теряет изменение.

Однако сеттеры реализуются только во время выполнения, поэтому

<Setter Property="Canvas.Left" Value="500" /> 

будет запускаться только после того, как объекты были сгенерированы и, следовательно, имеют относительную связь.

В противном случае вы можете использовать маржу, которая принадлежит объекту кнопки, но снова интерпретируется только во время выполнения.

person MikeT    schedule 18.01.2013