Windows Forms UserControls hosted in WPF spilling over side of window - wpf

I'm converting an old WinForms app to WPF. To speed the migration, I'd like to host as many of the old app's UserControls as possible in WindowsFormsHost elements.
When I do, however, the controls seem to spill over the side of the window! It's as if the hosted control believes the window is about 20% wider than it actually is.
To illustrate what I mean, here's a shot of the WinForms control in the designer:
And here's a shot of the control once it's hosted in the app:
Has anyone else seen this before? What is this caused by, and how do I fix it?
The WindowsFormsHost element is inside a TabControl's TabItem, if that makes any difference.
Edit: Here is the relevant XML:
<Window x:Class="MyWPFApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:forms="clr-namespace:MyWinFormsApp;assembly=MyWinFormsApp"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<!-- Grid Row 1 -->
<!-- Other controls here in row 1 -->
<!-- Grid Row 2 -->
<TabControl Grid.Row="2">
<TabItem Header="Advanced">
<WindowsFormsHost>
<forms:BinaryCommandControl/>
</WindowsFormsHost>
</TabItem>
<TabItem Header="Options">
<WindowsFormsHost>
<forms:OptionsControl/>
</WindowsFormsHost>
</TabItem>
</TabControl>
</Grid>
</Window>
BinaryCommandControl and OptionsControl are both custom WinForms UserControl elements.

Related

How can we show UWP user control on vertical-top edge of the parent window?

Following XAML in this Microsoft tutorial is showing too much gap between the top edge of the parent window and the UWP user control. Question: How can we make the user control align to the top edge of parent window? Remark: The VerticalAlignment="Top" in the StackPanel below does not help. This question is something similar to this post but in a different context.
<UserControl
x:Class="ClassLibUWP_inside_WPF.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibUWP_inside_WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
d:DesignWidth="400" Height="329">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="211*"/>
<ColumnDefinition Width="189*"/>
</Grid.ColumnDefinitions>
<StackPanel Background="LightCoral" Grid.ColumnSpan="2">
<TextBlock>This is a simple custom UWP control</TextBlock>
<Rectangle Fill="Blue" Height="93" Width="100"/>
<TextBlock Text="{x:Bind XamlIslandMessage}" FontSize="50"></TextBlock>
<winui:RatingControl Height="32" />
</StackPanel>
</Grid>
</UserControl>
When you run the app built in the above tutorial, you get the following screen showing the above UWP user control:
I would instead like to display it as follows [notice about no gap between window title and the red stack panel]:
The UserControl has a fixed height that is smaller than the height of the window and thus is vertically centered in the window. Setting VerticalAlignment="Top" on the WindowsXamlHost should give what you want.

Opening new UserControl in MainWindow erases all empty rows

Once I run the program, it opens a UserControl in my MainWindow. The UserControl is a Menu consisting of 3 buttons.
Image of the UserControl:
Menu
The code behind Main Window:
<Window
...
Title="MainWindow" Height="350" Width="525" SizeToContent="WidthAndHeight" >
<Window.DataContext>
<ViewModels:MainWindowViewModel />
</Window.DataContext>
<ContentControl Content="{Binding CurrentViewModel}"/> //Inserts a UserControl
The code behind Menu UserControl:
<UserControl
...
d:DesignHeight="90" d:DesignWidth="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*"/> //Problem
<RowDefinition Height="100*"/>
<RowDefinition Height="100*"/> //Problem
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Margin="30,0" Content="First" Command="{Binding DataContext.SwitchToNextUserControl,
RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Mode=OneWay}" />
<Button Grid.Row="1" Grid.Column="1" Margin="30,0" Content="Second"/>
<Button Grid.Row="1" Grid.Column="2" Margin="30,0" Content="Third"/>
</Grid>
THE PROBLEM:
Once the menu is opened, the empty rows (those without buttons, first and third) get collapsed (or just height to 0?), as shown: Running program
I can get over it with setting MinHeight for every row, but it works only on pixels. I'd like them to work in the method of stars ("*"). I guess I could set their height from code behind (using stars), but just the thought of it makes me feel like I rub my right ear with left hand.
Also, once I click on the "First" button, some other UserControl is opened in the window, instead of the "Menu" one, and its rows are also collapsed. Just mentioning it.
So the question is, what should I do to make my UserControls appear just as they look in designer?
You should remove to SizeToContent="WidthAndHeight" from your window XAML.
This causes the height of the window to shrink to fit the size of the UserControl (and effectively the height of the middle Button).

Wpf application with a fixed panel

I need to create a Wpf application with this type of navigation:
A main screen with a fixed top panel, and the rest of the window that acts as a container for other views. The container can be populated with 0 or 1 views - there's never a situation when 2 or more windows should be seen at the time in this container.
I've added this very childish drawing I made:
The top green panel is the navigation panel, and when pressing "A" button, I need viewA to be opened in the red part of the window.
Similarly, when pressing "B" button, I need viewB to be opened in the red part of the window instead of viewA.
My questions:
What objects should I use to represent viewA, viewB and the containing window? Are these Windows? Pages?
What is the best way of switching between viewA and viewB? I prefer avoiding loading both viewA and viewB (and any other view I'll have) into memory and just hide\show them..
Thanks.
You could put all the "Green" stuff in directly in your window and "Red" stuff (UserControl likely) inside a ContentControl and then bind the Content property of that to the red's stuff. So it'd be like this:
<Window x:Class="garbage.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--Green stuff-->
<Button Content="A" />
<Button Content="B" Grid.Column="1"/>
<ContentControl Grid.Row="1" Grid.ColumnSpan="2" Content="{Binding RedStuff}">
</ContentControl>
</Grid>

Scrollbar of a webbrowser control doesn't work correctly if enclosed in a tabcontrol

I have a program that has use of a webbrowser control. When enclosed in the main grid something like this:
<grid>
<WebBrowser x:Name="webBrowser" .../>
</grid>
The scrollbars work like they should, it goes to the extremes of the page.
however in if i want to put the webbrowser control in a tabcontrol, say because i wanted a tabbed browser, with the code like this
<grid>
<tabcontrol ...>
<tabitem ... >
<grid....>
<webBrowser x:Name="webBrowser1" />
</grid>
</tabitem>
</grid>
The scrollbars of the webbrowser control are not scrolling to the ends of the page, instead it it stops about 10% from the end horizontally and vertically.
Is there a way to get s tabbed browsercontrol that doesn't truncate the page?
Here is the more detailed code
<tabcontrol Height="500" HorizontalAlignment="Left" Margin="0,272,0,0" Name="tabControl1" VerticalAlignment="Top" Width=1000>
<Tabitem Header="FlexWebApp" Name="FWA" scrollViewer.VerticalSchollBarVisibility="Auto">
<grid Schrollviewer.VerticalScrollbarvisibility="hidden" name="FWAGrid>
<WebBrowser Name="WFWA" Source="pathToApplication"/>
</Grid>
</TabItem>
<TabItem header= AnalyseFWA Name="AFWA ...>
<Tabitem Header="SLWebApp" Name="SLA" scrollViewer.VerticalSchollBarVisibility="Auto">
<grid Schrollviewer.VerticalScrollbarvisibility="hidden" name="SLAGrid>
<WebBrowser Name="WSLA" Source="pathToApplication"/>
<TabItem header= AnalyseSLA Name="ASLA ...>
</Grid>
</TabItem>
So if it's not apparent the webbrowsers are directed to one silverlight app and one flex app both apps get truncated. In fact on both cases, the grid that encloses the apps' scrollbar is always visible despite the hidden attribute.
The truncation does not occur on regular browsers.
Could it be that the apps are misreporting its size?
Can you post more of your XAML?
I couldn't duplicate your issue. I created a new WPF Application project in Visual Studio 2010 and changed only the XAML and I did not have this issue.
<Window x:Class="TestBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl>
<TabItem Header="Rhyous.com">
<Grid>
<WebBrowser x:Name="WebBrowser" Source="http://www.rhyous.com"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
The entire web page was displayed.
So my guess is that you will see the same if you create a sample project. Then you can start adding what you did in your real project to your sample until you find what is really breaking it.

WPF TabControl Children

This is my current Scenario: I have several UserControls inside different TabItems on a single TabControl in a WPF Window. Something Like:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="S.C.A.R" WindowState="Maximized">
<TabControl Name="MainTabControl">
<TabItem Name="TabOps">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="30"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Local:ServiceList Height="Auto" CanInsert="True" CanCollapse="True" Grid.ColumnSpan="3" x:Name="SL" RecordState="Edit"/>
<Local:ReservationList CanCollapse="True" Grid.Row="1" RecordState="Edit" x:Name="RL"/>
<Local:DriverList CanDelete="False" CanInsert="False" CanCollapse="True" Grid.Row="1" Grid.Column="2" RecordState="Edit" x:Name="DL"/>
<Local:CustomerForm CanDelete="False" CanInsert="False" Grid.Row="2" Grid.ColumnSpan="3" RecordState="View" x:Name="CL"/>
</Grid>
</TabItem>
<TabItemItem Name="TabCodes">
<Local:CustomerList x:Name="CustomerCRUD" RecordState="View"/>
</TabItem>
<Button Grid.Row="1" Content="TEST" Click="Button_Click"/>
</Grid>
</Border>
</Window>
Sorry for the indentation. For some reason I can't get the code properly indented here :(
What I need to do is to determine (preferably in the TabControl.Load Method, which of my different UserControls are currently visible. I need to do this in a dynamic way, I cannot hardcode the relationship between the TabItems and their children, something like:
if (TabControl.SelectedItem is XXXX)... is not possible here, because this is a Dynamic UI and I have no way to know which controls are there up front.
I've been digging a little bit and found out that the TabItem controls do not appear in the Visual tree of their "children". I only see a ContentPresenter, and then the TabControl itself. It looks like the tabItems do not "contain" their own content, so I could not, for example, do a FindAncestor to the Tab Items.
Another interesting fact is that the Loaded event of my usercontrols is being called on startup. Regardless of whether or not they're visible on screen.
An ideal scenario will be to find an event that is only fired on my Usercontrols when the TabItem they are under gets selected.
Appreciate any ideas. Thanks in advance
You should be able to leverage the VisualTreeHelper and consequentrly this answer on SO to provide the TabItem.Content returned object and look for the your specified type, UserControl in this instance.
NOTE:
For additional details please see the comments which transpired in the SO's question.

Resources