This is my first question in StackOverflow. Due to lack of reputations, I couldn't post any links or images. I've been working on the following issue for more than 2 days. Any help would greatly be appreciated.
Before I get into my question, here is what I have and what I'm expecting:
- I have a Windows Form which hosts WPF in an ElementHost control.
- And then, I have a Winforms UserControl similar to DateTimePicker. This
is hosted inside a WindowsFormsHost control.
The above scenario is un-avoidable for the following reasons:
- The authorization dialog to all our applications is developed in Winforms, and takes a Winforms instance as its parameter. There is no WPF version introduced yet. Therefore, I had to use an ElementHost to host my View inside the Windows Form.
- The Winforms control hosted inside my WPF is also un-avoidable. We have our own DateTime Winforms UserControl that behaves similar to the DateTimePicker Winforms control, but has lot more complexities involved. So, replacing this control with a WPF version is out of question.
Expected Functionality:
I have a
WPF control (say, a textbox)
A DateTime Winforms UserControl that I was mentioning above.
And a Cancel button that basically resets the above controls.
When I hit the Cancel button, I'm publishing an event from the ViewModel
, say RunViewModel to the WPF UserControl code behind file, say RunView.xaml.cs.
eventAggregator.GetEvent<ResetDateTimeEvent>().Publish(true);
In the code behind file, I've subscribed to the event as follows
eventAggregator.GetEvent<ResetDateTimeEvent>().Subscribe(ResetDateTimeHandler);
The WPF control resets to its default value, but the DateTime UserControl does not reset.
So, for testing purposes, I removed the ElementHost control, and just had my WPF View with a WindowsFormsHost control that hosts the DateTime Winforms UserControl, and a WPF "Cancel" button.
When I click on the button, the value on the DateTime control resets to its default value.
Then, I thought this might be an issue with my DateTime Winforms UserControl. So, I replaced my DateTime Winforms UserControl with a Winforms Textbox control in my actual application. So now the nesting is as follows:
WinForms-ElementHost-WPF-WindowsFormsHost-Winforms Textbox
Here is the xaml code.
<WindowsFormsHost x:Name="ReportFromDtTmHost" Margin="8,0" Grid.Column="0"
LostFocus="ReportFromDtTmHost_LostFocus">
<WindowsFormsHost.Child>
<winforms:TextBox x:Name="ReportFromDateTime"/>
</WindowsFormsHost.Child>
</WindowsFormsHost>
On Initial load, I’m loading the Textbox
with Initial Load Text
text
private void Window_Loaded(object sender, EventArgs e)
{
ReportFromDateTime.Text = "Initial Load Text";
}
As I was mentioning above, when I hit the Cancel button, this is what happens:
Publish the event from ViewModel
eventAggregator.GetEvent().Publish(true);
Subscribe to the event in the code behind file (xaml.cs):
eventAggregator.GetEvent().Subscribe(ResetDateTimeHandler);
EventHandler for the published event.
private void ResetDateTimeHandler(bool cancelClicked) { ReportFromDateTime.Text = "Reset to Default"; }
As you can see in the above code, I’m resetting the Text on clicking the Cancel button.
During Debugging, I could see the Text property being changed to "Reset to Default", but the UI does not show these changes.
Here is the wierd part:
The Child property on the WindowsFormsHost control is different from the actual “ReportFromDateTime” Textbox control.
While debugging, I could see that the Child and Name property on the WindowsFormsHost control were different. The Name property is empty,
ReportFromDtTmHost.Child.Name = ""
which rather should be ReportFromDateTime.
It almost seems like the Host and the Child controls are getting re-created.
As far as I see it, I think the extra level of nesting (WinForms-ElementHost-WPF-WindowsFormsHost-Winforms Textbox) might be causing issues during the interoperations between WPF and Winforms.
I’ve done a lot of research and searched lot of links for suggestions. I found none pointing out this issue. Some of them were close. Here are a couple of links:
The this suggests to reproduce the message loop under the “Surrogate Windows Forma Message Loop” section.
Here is one more link that explains the issue with nesting under the Nesting section.
I apologize for being verbose. Just wanted you guys to get a clear picture of my problem. Please let me know if you have any questions regarding the post. Any suggestions would be greatly appreciated.
EDIT:
We were able to resolve the issue, but still, it is a work-around. Here is what we did: There were two ways to resolve this issue, but both were related to using static.
Static Winforms control:
We used the following static Winforms control
public static class ControlHolder
{
public static TextBox ReportFromDateTimeInstance;
}
In the OnChanged event of the "actual" control, we dump the actual control, ReportFromDateTime to the static control, ReportFromDateTimeInstance.
private void ReportFromDateTime_TextChanged(object sender, EventArgs e)
{
ControlHolder.ReportFromDateTimeInstance = (TextBox)sender;
}
And from then on, wherever we update the actual control (as in ResetDateTimeHandler
method), we update the static control
private void ResetDateTimeHandler(bool cancelClicked)
{
ControlHolder.ReportFromDateTimeInstance = "Text changed";
}
This shows the updated value on the Front-End
Static EventAggregator
This work-around was provided by one of our colleague.
In this case, we are using our actual control, ReportFromDateTime, rather than the static control, ControlHolder.ReportFromDateTimeInstance
We used a static event aggregator for publishing/subscribing the ResetDateTimeEvent instead of using the Event Aggregator instance provided by Unity Container. So, instead of
eventAggregator.GetEvent<ResetDateTimeEvent>.Publish(true);
we used:
ResetDateTimeEvent.Instance.Publish(true);
And in the subscription:
ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);
I know that we need not use a static event aggregator in this scenario since we are using the instance provided by Unity Container (which makes sure that a single instance is shared by all the ViewModels), but this also has resolved the issue.
So, I'm still confused on why the above two scenarios are solving the problem. Is it the static-ness that is solving the issue ?
As I was already saying, I feel that the controls are getting re-created, and by the time we have the controls in hand, they have been already re-created.
Any suggestions would greatly be appreciated.