Скрыть элемент управления, когда другой элемент перекрывает его

У меня довольно большая проблема с элементами управления окнами, размещенными в WPF. Когда, например, пользователь прокручивает окно, размещенный элемент управления переходит в верхнюю часть окна, хотя он должен быть скрыт.

Я знаю, что это известная проблема и поведение по умолчанию размещенных элементов управления, но я думаю, что ее можно решить, если видимость элемента управления каким-либо образом связана с: перекрывают ли его другие элементы управления или нет. Если другие элементы управления перекрываются, он должен стать Свернутым или Скрытым, в противном случае он должен быть Видимым.

Я сделал какое-то решение для этого, но я сделал это для события ScrollChanged объекта ScrollViewer, и оно работает только в особых ситуациях. Если кто-то знает, как добиться этого с помощью связывания, чтобы его можно было применить к любому размещенному элементу управления, поделитесь своими идеями.

1 ответ

Для этой же проблемы мы реализовали нечто любопытное...

Хост форм Windows не зависит от Z-порядка, поэтому средство просмотра прокрутки не сможет частично скрыть / обрезать его для области, которая видна под средством просмотра прокрутки.

Итак, у нас было два варианта...

  1. Используйте хост формы Windows для размещения в нем остальной части пользовательского интерфейса WPF, что означает, что мы отменяем владение пользовательским интерфейсом. WindowsFormsHost должен содержать весь пользовательский интерфейс, имеющий средство просмотра с прокруткой на основе WinForms, которое, в свою очередь, будет содержать пользовательский интерфейс WPF.

  2. Реализуйте смещение прокрутки для вычисленной высоты хоста оконных форм, и когда пользовательские прокрутки добавляют это смещение к позиции наблюдателя прокрутки и скрывают хост форм ветра (Visibility = Hidden и НЕ Collapsed). Таким образом, это дает эффект, что вы не можете частично прокрутить хост winforms, но полностью прокрутить его из средства просмотра прокрутки. И потому что winformshost является Hidden (не свернутый) он продолжает занимать такую ​​большую высоту внутри невидимой области под средством просмотра прокрутки (таким образом сохраняя свое положение прокрутки).

Дайте мне знать, если это направит вас в правильном направлении.

Вы можете сделать небольшой трюк. Когда вы объявляетеWindowsFormsHost, его родительский элемент является первым компонентом HWND. Обычно это корневое окно. Таким образом, область обрезки элементов управления - это все окно. Я покажу пример с WPFScrollViewer.

<Window>
    <Grid>
        <ScrollViewer Margin="20,50">
            <ItemsControl ItemsSource="{StaticResource StringArray}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <WindowsFormsHost>
                            <wf:Button />
                        </WindowsFormsHost>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
</Window>

В этом случае поведение будет таким, как вы описали. Кнопки будут внеScrollViewerграницы. Но есть способ создать "промежуточный" элемент HWND для обрезкиWinForms площадь над ScrollViewer. Просто поместите еще одинWindowsFormsHost с ElementHost как показано ниже:

<Grid>
    <WindowsFormsHost Margin="20,50">
        <ElementHost x:Name="This is clip container">
            <ScrollViewer>
                <ItemsControl ItemsSource="{StaticResource StringArray}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <WindowsFormsHost>
                                <wf:Button />
                            </WindowsFormsHost>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </ScrollViewer>
        </ElementHost>
    </WindowsFormsHost>
</Grid>

Теперь область клипа для кнопок ElementHost а также WinForms Buttons будет обрезаться им при прокрутке. Также вы можете создатьControlTemplate за ContentContol и повторно используйте его там, где вам это нужно.

<ControlTemplate x:Key="ClipConteiner" TargetType="{x:Type ContentControl}">
    <WindowsFormsHost>
        <ElementHost>
            <ContentPresenter />
        </ElementHost>
    </WindowsFormsHost>
</ControlTemplate>
<Grid>
    <ContentControl Template="{StaticResource ClipConteiner}" Margin="20,50">
        <ScrollViewer>
            <ItemsControl ItemsSource="{StaticResource StringArray}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <WindowsFormsHost>
                            <wf:Button />
                        </WindowsFormsHost>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </ContentControl>
</Grid>
Другие вопросы по тегам