Обрезание WPF, даже если оно не требуется - как его отключить?

Мне нужно вывести некоторый контент из ListBox, как указано в DataTemplate для ListBox.ItemTemplate. Я использую RenderTransform, но содержимое обрезается на ListBox границах. ClipToBounds - это False для всего визуального дерева.

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

Как я могу решить эту проблему? Вот код XAML, который я хочу исправить. Обратите внимание: вся левая часть прямоугольника отсутствует.

    <ListBox>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Rectangle Fill="Red" Stroke="Green" StrokeThickness="4" Width="100" Height="50">
                    <Rectangle.RenderTransform>
                        <TranslateTransform X="-50" />
                    </Rectangle.RenderTransform>
                </Rectangle>
            </DataTemplate>
        </ListBox.ItemTemplate>

        42
    </ListBox>

person wpfwannabe    schedule 31.01.2011    source источник


Ответы (2)


ListBoxItem обрезаются ScrollViewer в шаблоне ListBox. Чтобы обойти это, я думаю, вам нужно удалить ScrollViewer из шаблона, и если вам нужна прокрутка, вы можете обернуть ListBox в ScrollViewer

<ScrollViewer HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto">
    <ListBox Margin="100,10,0,0">
        <ListBox.Template>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
                    <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </ListBox.Template>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Rectangle Fill="Red" Stroke="Green" StrokeThickness="4" Width="100" Height="50">
                    <Rectangle.RenderTransform>
                        <TranslateTransform X="-50" />
                    </Rectangle.RenderTransform>
                </Rectangle>
            </DataTemplate>
        </ListBox.ItemTemplate> 42
    </ListBox>
</ScrollViewer>

Обновить

ScrollViewer в шаблоне сгенерирует ScrollContentPresenter, который, в свою очередь, будет иметь следующие GetLayoutClip

protected override Geometry GetLayoutClip(Size layoutSlotSize)
{
    return new RectangleGeometry(new Rect(base.RenderSize));
}

Этот класс является запечатанным, поэтому вы не можете наследовать его, чтобы переопределить этот метод. Вам нужно будет реализовать свой собственный ScrollContentPresenter (например, MyScrollContentPresenter) и, вероятно, свой собственный ScrollViewer, который также использует MyScrollContentPresenter, чтобы эта работа работала (и если вы вернете null в этом методе, я думаю, что некоторые элементы ниже границ ListBox могут стать видимыми как хорошо)

person Fredrik Hedblad    schedule 01.02.2011
comment
Кажется, вы на месте! Но мне нужно это ScrollViewer на прежнем месте. Вы знаете, что такого особенного во внутренней реализации ScrollVeiwer, что меня задевает? Это что-то, что можно переопределить в производном классе? Я где-то читал, что GetLayoutClip виноват, но не могу заставить его работать по-своему. - person wpfwannabe; 01.02.2011
comment
@wpfwannabe: Обновил мой ответ. Вы правы, что GetLayoutClip проблема. К сожалению, на этот раз он находится в классе Sealed (ScrollContentPresenter), поэтому вы не можете наследовать его. Насколько я знаю, для этого потребуется много работы. - person Fredrik Hedblad; 01.02.2011
comment
Ваш ответ великолепен! Большая помощь! Большое спасибо! Тем временем я изменил свой макет по-другому, применив своего рода разделение ListBoxItem, которое позволяет мне отображать плавающее содержимое внутри ListBox, и, таким образом, мне больше не нужна вся эта ScrollViewer malarkey. В большинстве случаев можно найти другое решение одной и той же проблемы. На этот раз мне пришлось немного изменить свои шаблоны, чтобы все работало так, как ожидалось, но, похоже, это намного проще, чем создавать свой собственный ScrollViewer. Спасибо еще раз! - person wpfwannabe; 01.02.2011
comment
@wpfwannabe: Нет проблем :) Да, ваше новое решение кажется намного лучшим вариантом! Удачи - person Fredrik Hedblad; 01.02.2011

Я случайно наткнулся на решение этой проблемы, работая над ней. Если вы измените HorizontalScrollMode и VerticalScrollMode ScrollViewer на «Отключено» в шаблоне стиля, он перестанет обрезать в каждом направлении соответственно.

Изменить: может не работать для WPF. Я тестировал приложение UWP. Рассматриваемые поля:

ScrollViewer.HorizontalScrollMode = "Отключено"

ScrollViewer.VerticalScrollMode = "Отключено"

person Andrew    schedule 18.08.2016
comment
В WPF нет такого свойства, как HorizontalScrollMode. - person vlaku; 06.01.2017
comment
Извините, я должен был упомянуть, я протестировал его и заставил его работать в приложениях UWP, и я предполагал, что он будет применяться к WPF. Хотя нет. - person Andrew; 15.01.2017