Hide control when another control overlaps it
I am having pretty big problem with windows forms controls hosted in WPF. When, for example, user scrolls the window, the hosted control g开发者_开发问答oes on top of the window, although it should be hidden.
I know this is known problem, and default behavior of hosted controls, but I think it can be solved if control's visibility is somehow binded with: whether other controls overlap it, or not. If other controls are overlapping, it should become Collapsed or Hidden, if not, it should be Visible.
I made some kind of solution for this, but I did it on ScrollChanged event of a ScrollViewer and it works only in special situations. If somebody knows how to achieve that with binding, so it can be applied to any hosted control, please share your ideas.
For this same problem, we implemented something curious...
Windows forms host is unaffected by Z-order so scroll viewer wont be able to partially hide/ clip it for the area which is visible under the scrollviewer.
So we had two options...
Use Windows form host to host rest of the WPF UI in it which means we reverse the ownership of the UI. The WindowsFormsHost must host all the UI in it having a WinForms based scroll viewer which in turn will host the WPF UI.
Implement a scroll offset for calculated height of the windows forms host and when user scrolls add this offset to the scrollviewer's position and hide the windforms host yourself (
Visibility = Hidden
and NOTCollapsed
). This way it gives an effect that you cannot partially scroll a winforms host but that scroll it completely off the scroll viewer. And because winformshost isHidden
(not collapsed) it continues to occupy that much height inside the invisible area under the scroll viewer (thereby maintaining its scroll position).
Let me know if this guides you in correct direction.
You can do a little trick. When you declare an WindowsFormsHost
, it's parent is first HWND component. Usually it's root window. So, clip area for controls is whole window.
I'll show an example with 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>
In this case behaviour will be like you described. Buttons will be out of ScrollViewer
bounds.
But there's a way to create "intermediate" HWND item to clip WinForms
area over ScrollViewer
. Just place another WindowsFormsHost
with ElementHost
like below:
<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>
Now clip area for buttons is ElementHost
and WinForms
Button
s will be clipped by it on scrolling.
Also you can create ControlTemplate
for ContentContol
and reuse it where you need it.
<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>
精彩评论