我在WPF中托管windows窗体控件时遇到了很大的问题。例如,当用户滚动窗口时,托管控件将位于窗口的顶部,尽管它应该是隐藏的。
我知道这是已知的问题,也是托管控件的默认行为,但我认为如果控件的可见性以某种方式与:是否与其他控件重叠,它可以解决。如果其他控件重叠,它应该变成折叠或隐藏,如果没有,它应该是可见的。
我为此做了一些解决方案,但我在ScrollViewer的ScrollChanged事件上做了,它只在特殊情况下起作用。如果有人知道如何通过绑定实现这一点,那么它可以应用于任何托管控件,请分享您的想法。
对于同样的问题,我们实现了一些奇怪的东西…
Windows窗体主机不受z轴顺序的影响,因此滚动查看器将无法部分隐藏/剪辑它,以便在滚动查看器下可见的区域。
所以我们有两个选择…
-
使用Windows form host来托管WPF UI的其余部分,这意味着我们颠倒了UI的所有权。WindowsFormsHost必须承载所有的UI,它有一个基于WinForms的滚动查看器,而滚动查看器又将承载WPF UI。
-
实现窗口窗体主机计算高度的滚动偏移量,当用户滚动时,将此偏移量添加到scrollviewer的位置并隐藏自己的windforms主机(
Visibility = Hidden
和NOTCollapsed
)。这样做的效果是,您不能部分滚动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
。把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
, 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>