Calling winforms hosting Wpf grid cause error - wpf

I have a WinForms application that acts as a service(so no actual UI), but it is a WinForms application.
In this application I a form that has an ElementHost and in the elementHost I have a WPF grid.
In one of my classes I have this code:
Dim frm1 As New frmHostWpfGrid '->HERE I get the error
frm1.WpfGrid.WpfGridControl.BeginDataUpdate()
frm1.WpfGrid.WpfGridControl.ItemsSource = Nothing
frm1.WpfGrid.WpfGridControl.RestoreLayoutFromStream(LayoutStream)
frm1.WpfGrid.WpfGridControl.ItemsSource = mdtData
frm1.WpfGrid.WpfGridControl.EndDataUpdate()
THe error I get is:
The calling thread must be STA, because many UI components require this.
When I tried with a WinForms form and a grid I didn't have this problem.
PS1. Notice that I don't want to show the form
PS2. I tried to fill directly a WPF grid without a form and I got the same error

You are trying to create UI objects on a non UI thread. Its hard to tell exactly what is causing the error without seeing your form initialization code where it must be setting up some of the WPF elements.
I will need to know more about frmHostWpfGrid to give you an exact answer.

Related

Refresh the UI of Windows Form

I'm working on an old project that supports Windows Forms.
This project contains some ResourceManager for the support of a few localizations. The idea is that you call ResourceManager["SomeResource"] instead of Resource.SomeResource and it returns you a localized string.
And these localized strings are used in the code of the initialization of the form. For example, you have Form1, and in Form1.Design.cs there is some code like this:
Label label1 = new Label();
label1.Text = ResourceManager["SomeResource"];
So the label will be created with an already localized string in the Text.
And we need to add the functionality of changing the UI language without reloading the Form.
We can just set the every Text property of every controls again. But it's a lot of code, the form contains a lot of controls.
We can call the Form.InitializeComponents(), this method will recreate all controls with new localized strings, but in some cases, it works slowly because it reloads some big data again.
Is there some other way to refresh all UI controls and get the new localized strings? Do Windows Forms support some mechanism like Binding in the WPF to create the "connection" between the Text properties and localized resources?
I think that you can achieve this by use of Invalidate() either on the form itself or on a container control that your other controls may be encompassed by.

vb.net - Can I load a wpf form into a canvas/grid control?

I trying to see if its possible to load a form into a canvas or grid control in wpf with vb.net.
I'm not very familiar with WPF at all, usually working with Winforms more than anything else, however I need to take advantage of the far superior transparancy options offered by WPF for this current project, so need to see if I can crack this.
In Winforms, I'd normally have a panel (call it contentpanel or mainpanel etc) and then whenever I needed to I could easily load another form into that panel dynamically and keep everything neat and tidy in one form when presented to the user, so something like...
dim newforminstance as form1
newforminstance.toplevel = true
newforminstance.topmost = false
contentpanel.controls.add(newforminstance)
newforminstance.show
That works a treat in Winforms; Is there a similar way to achieve this functionality in WPF?
Thanks in advance.

ToolStripTextBox, ToolStripComboBox not automated

In UI Automation, when automating the toolstrip items we are facing an issue which is described below
I am adding toolstrip items as follows
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripButton1,
this.toolStripButton2,
this.toolStripComboBox1,
this.toolStripButton3});
When running the UI Automation(System.Windows.Automation), UI automation finds the controls till toolStripButton2 (i.e) controls on the left side of toolstripcombobox is getting recognized but on the controls on the right side.(If i make the combobox to go the right most control everything works fine)
Note: In Inspect.exe tool from windows kits, all the controls are shown but when trying to access the last toolStripButton3 returns null.
Here i have attached the simplified code, the buttonCollection is expected to get 3 buttons but it gets only two in my case.
AutomationElement toolstrip = viewTab.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "toolStrip1"));
AutomationElementCollection buttonCollection = toolstrip.FindAll(TreeScope.Children,
new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "button"));
Both ToolStripTextBox and ToolStripComboBox are showing the same behavior.
I would like know what is going wrong my approach.
I've posted one approach which would allow you to access all the buttons, in response to your question at https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/2363de9f-3bf0-48dc-a914-1eef5bcf1482/toolstriptextbox-toolstripcombobox-not-automated?forum=windowsaccessibilityandautomation.
Thanks,
Guy

Hosted Winform control does not respond to events from WPF

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.
I've done the same thing before in an app that had a WPF control inside of a WinForms control. The WPF used Prism/Unity (later switched to MEF) to start everything up. However, this created a whole new EventAggregator by default in the bootstrapper, so I had override the default IEventAggregator in the container with a static one b/c the WinForm side had already been created and was using its own IEventAggregator instance. The symptom was similar in that published events were not received.
In a mixed system such as yours, singletons are great for ensuring that everything's feeding off of the same reference, especially when your startup is in stages (WinForms then WPF).
Simple answer: yes, use singletons for shared references between WinForms code and WPF code. Those singletons can be fed into the container in the WPF bootstrapper so that injection still occurs in the WPF side, too.

Weird scrollbar UI in hosted WPF composite control

My windows forms application hosts AvalonEdit (the composite WPF control in question) in one of its forms to cater to its text editing requirements. Here's the code I use:
WPFHost = gcnew ElementHost();
TextField = gcnew AvalonEdit::TextEditor();
WPFHost->Dock = DockStyle::Fill;
WPFHost->Child = TextField;
TextField->Options->AllowScrollBelowDocument = false;
TextField->Options->EnableEmailHyperlinks = false;
TextField->Options->EnableHyperlinks = true;
TextField->Options->RequireControlModifierForHyperlinkClick = true;
TextField->ShowLineNumbers = true;
ContainerControl->Controls->Add(WPFHost); // the container is a panel
The code compiles and executes fine, except for the scrollbars - http://dl.dropbox.com/u/2584752/avalonEditBug.png . Right clicking on what's left of the bar raises an ArgumentOutOfRange exception.
Strangely, I wasn't able to reproduce the issue when I tried hosting the control in a newly created sample project. 'mI using the latest build of the text editor and have all the requisite assemblies installed.
EDIT: Wrapping the editor in a usercontrol doesn't help either.
You say that the control works fine in a new/blank project but fails in the one you need makes me wonder about conflicts more than anything. In the project you're really wanting compared to the project it worked in what are the differences? .NET version? Referencing an assembly from a directory in one but out of the GAC in another?
It's hard to say that the control is messing up for you when you've got it working elsewhere, so the only thing I can suggest is just dive deep into the differences of the two projects.
Good luck.
This looks like a layout error to me. Maybe WPFHost measures the TextField unexpectedly.
I can suggest setting specific Width and Height on the TextField itself. If this fixes the problem you can adjust those as the size of the WPFHost control changes or try setting the MaxHeight/Width, sometimes they help and save some code for Width/Height updates.
try to create a WPF grid as a child of ElementHost, and place the editor inside that grid. On Other way, is to create an UserControl have the editor in that control and use the control inside your Winform app. Such approach helped me a couple of times.
I've implemented a workaround for the issue as mentioned in this thread [ Synchronizing a WPF ScrollViewer with a WinForms ScrollBar ].

Resources