当另一个控件与其重叠时隐藏该控件

本文关键字:控件 隐藏 重叠 另一个 | 更新日期: 2023-09-27 18:09:13

我在WPF中托管windows窗体控件时遇到了很大的问题。例如,当用户滚动窗口时,托管控件将位于窗口的顶部,尽管它应该是隐藏的。

我知道这是已知的问题,也是托管控件的默认行为,但我认为如果控件的可见性以某种方式与:是否与其他控件重叠,它可以解决。如果其他控件重叠,它应该变成折叠或隐藏,如果没有,它应该是可见的。

我为此做了一些解决方案,但我在ScrollViewer的ScrollChanged事件上做了,它只在特殊情况下起作用。如果有人知道如何通过绑定实现这一点,那么它可以应用于任何托管控件,请分享您的想法。

当另一个控件与其重叠时隐藏该控件

对于同样的问题,我们实现了一些奇怪的东西…

Windows窗体主机不受z轴顺序的影响,因此滚动查看器将无法部分隐藏/剪辑它,以便在滚动查看器下可见的区域。

所以我们有两个选择…

  1. 使用Windows form host来托管WPF UI的其余部分,这意味着我们颠倒了UI的所有权。WindowsFormsHost必须承载所有的UI,它有一个基于WinForms的滚动查看器,而滚动查看器又将承载WPF UI。

  2. 实现窗口窗体主机计算高度的滚动偏移量,当用户滚动时,将此偏移量添加到scrollviewer的位置并隐藏自己的windforms主机(Visibility = HiddenNOT Collapsed)。这样做的效果是,您不能部分滚动winforms主机,而是将其完全滚动出滚动查看器。并且因为winformshost是Hidden(没有崩溃),它继续在滚动查看器下的不可见区域内占据那么多高度(从而保持其滚动位置)。

你可以做一个小技巧。当声明WindowsFormsHost时,它的父组件是第一个HWND组件。通常是根窗口。控件的剪辑区域是整个窗口。我将展示一个使用WPF ScrollViewer的示例。

<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。把WindowsFormsHostElementHost放在下面:

<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>

现在按钮的剪辑区域是ElementHostWinForms, Button将在滚动时被它剪辑。你也可以为ContentContol创建ControlTemplate,并在你需要的地方重用它。

<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>