0
votes

I am trying to migrate an existing Winforms project into WPF. However: there are some user controls I need to leave as WinForm controls.

I have added a WinForms UserControl into a WPF Window. It consists of a RichTextBox and some buttons and labels. This is subclassed into various further user controls.

When I embed the UserControl into a WPF window it renders - but none of the buttons appear to do anything. When underlying processes update e.g. the RichTextBox it does not display the content. Yet when I inspect the textbox in debug I can see the content (though I have to click on 'base' to see this.)

[ One difference I have spotted - though it may not be relevant - is that when this control is on a WPF and non-working Visual Studio shows the object as 'sealed' but when in the original Winforms project when it is fully working it does not show as sealed. ]

I have added code to change the text in the labels - and they also firmly refuse to update: yet again I can see the text if I examine the label in debug mode.

This stack overflow question may address the same issue: WindowsFormsHost Winform pdfviewer control problem

but the answer didn't make a lot of sense to me: It mentioned replacing

new Window { Content = CreateContent(), Title = title }.Show();

But this is not a piece of code I recognise: I am using a xaml file with code behind and it's called up using

System.Windows.Application app = new System.Windows.Application(); 
app.Run(new FormWPFApp());

(where FormWPFApp is my name for the WPF window)

Here is the xaml header:-

<Window x:Class="ZedApp.FormWPFApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Printers="clr-namespace:ZedApp.UserControls.Printers"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

        Title="Conversion version" Height="661" Width="1559" Loaded="Window_Loaded">

Here is the xaml I use for the two UserControls (they both inherit from the same base class) :-

<WindowsFormsHost Height="430" HorizontalAlignment="Left" Margin="192,32,0,0" Name="windowsFormsHostTicketPrinter" VerticalAlignment="Top" Width="324" Grid.Row="1" Grid.Column="1">
    <Printers:TicketPrinter x:Name="ticketPrinter">
    </Printers:TicketPrinter>
</WindowsFormsHost>
<WindowsFormsHost Height="430" HorizontalAlignment="Left" Margin="522,32,0,0" Name="windowsFormsHostJournalPrinter" VerticalAlignment="Top" Width="324" Grid.Row="1" Grid.Column="1">
    <Printers:JournalPrinter x:Name="journalPrinter">
    </Printers:JournalPrinter>
</WindowsFormsHost>

[Another thing I have noticed is a method that clears the Rich Text Box on one of the windows starts kicking out errors of the following type if run under WindowsFormsHost in WPF - "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."

private void ClearRichTextBox(RichTextBox rtbToClear)
{
    if (rtbToClear.IsHandleCreated)
    {

        if (rtbToClear.InvokeRequired)
        {
            this.Invoke(new Action<RichTextBox>(ClearRichTextBox), new object[] {rtbToClear});
            return;
        }

        rtbToClear.Clear();
    }
}

]

What is the likely cause of this behaviour and what do I need to do to get the elements within the User Control working?

1

1 Answers

0
votes

Proper input interop with WinForms requires some cooperation between the host and the WPF input system. The topic Message Loops Between Win32 and WPF in the SDK explains this well. In your setup, the easiest way to make this happen is to use code like this:

Window w = new Window1();
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(w);
w.Show();

ElementHost.EnableModelessKeyboardInterop() essentially registers an input hook with the WinForms Application object (which normally runs the message loop) and calls ComponentDispatcher.RaiseThreadMessage().