Casting to ElementHost not possible? - c#

I have an VSTO Outlook Add-in (a kind of winforms app) and I am using an Outlook control that allows embedding a custom winforms user control.
Instead I want to embed an WPF user control so I create a Winforms user control and place within it an ElementHost. Finally I embed the WPF user control within the ElementHost.
So the structure is:
VSTO Outlook Add-in <---> Outlook Control <---> Winforms User Control <----> ElementHost <----> WPF user control
Now from my WPF user control, from its code-behind (*.xaml.cs) I am trying to access a method hosted in the winforms user control so I do below:
ElementHost eh = (ElementHost) this.Parent; <----- error
MyWinformUserControl winformUC = eh.Parent;
winformUC.MyMethod();
When trying to cast to ElementHost I get a compilation error that says:
CS0030: Cannot convert type 'System.Windows.DependencyObject' to 'System.Windows.Forms.Integration.ElementHost'
If I change to:
ElementHost eh = this.Parent as ElementHost;
then compiler says:
CS0039: Cannot convert type 'System.Windows.DependencyObject' to 'System.Windows.Forms.Integration.ElementHost' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.
So how can I cast into an ElementHost?

Assuming you have a MyWinFormsControl which has a DoSomething method, you can call it from WPF like this:
public partial class MyWPFControl : UserControl
{
public MyWPFControl()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var hwnd = PresentationSource.FromVisual(this) as HwndSource;
var host = System.Windows.Forms.Control.FromChildHandle(hwnd.Handle) as ElementHost;
var myUC = host.Parent as MyWinFormsControl;
myUC.DoSomething();
}
}
However, I'd suggest you revert the dependency and pass whatever you need to the WPF control. It could be passing the whole control, could be passing a delegate, or could be raising an event in the WPF control and handling in WinForms control.
public partial class MyWPFControl : UserControl
{
public MyWPFControl()
{
InitializeComponent();
}
public MyWinFormsControl Control { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
Control.DoSomething();
}
}
And here is MyWinFormsControl
public partial class MyWinFormsControl : UserControl
{
public MyWinFormsControl()
{
InitializeComponent();
((MyWPFControl)elementHost1.Child).Control = this;
}
public void DoSomething()
{
MessageBox.Show("Hi");
}
}

Related

Windows Forms C#: Access TabControl from UserControl

I have a TabControl and a UserControl interacting in the following way:
Each time a new tab is opened, the UserControl loads onto the new tab.
In the UserControl there's a Panel, a TexBox and a Button. Each time text is entered into the TexBox and the Button is pressed, it's supposed to update the title of the current tab
How do I access the tab title from within the UserControl?
Better if the user control does not know where it is embedded into.
Consider providing a TitleChanged event in the user control instead. Then it can be the responsibility of the consumer to update itself accordingly.
public class MyUserControl : UserControl
{
// [...]
public string Title { get; private set; }
public event EventHandler TitleChanged;
// [...]
private void MyTextBox_TextChanged(object sender, EventArgs e)
{
Title = MyTextBox.Text;
TitleChanged?.Invoke(this, EventArgs.Empty);
}
}
And the necessary code of the consumer class can be sg like this:
// after subscribing the myUserControl.TitleChanged event:
private void MyUserControl_TitleChanged(object sender, EventArgs e)
{
myTab.Text = myUserControl.Title;
}
Even better if you use data binding in the user form:
myTab.DataBindings.Add(nameof(TabPage.Text), myUserControl, nameof(MyUserControl.Title));

Changing panel control from inside the panel

I am creating an application using WinForms. I have panel in which I show a user control. Inside this user control I have a button. When I click the button, I want to clear the panel and show a different user control. I am trying to do that using the following code:
private void btnCreateOffer_Click(object sender, EventArgs e)
{
var myControl = new WindowsFormsDemo.View.CreateOffer();
MockUpForm.panMain.Controls.Clear();
MockUpForm.panMain.Controls.Add(myControl);
}
This works from the buttons placed directly in the parrent form, but when I use in inside the user control, it says:
'MockUpForm.panMain' is inaccessible due to its protection level
I suppose it has something to do with private/public classes. But I would rather have the "correct" solution, as opposed to just changing everything to public.
Any suggestions on how this is usually done?
Solution 1 (ugly):
Make panMain public in the designer:
Solution 2 (somewhat better):
Provide public methods to achieve such tasks safely:
// MockUpForm code:
public void ClearPanelControls()
{
panMain.Controls.Clear();
}
public void AddControlToPanel(Control c)
{
panMain.Controls.Add(c);
}
And then call these methods instead of publishing the full panel, which makes possible for example to dispose the whole panel and such things...
To access parent form's control from UserControl You can use delegate and event
something like this....
Windows Form (Parent Form) Code....
public Form1()
{
InitializeComponent();
userControl1.CreateOffer += UserControl1_CreateOffer;
}
private void UserControl1_CreateOffer()
{
var myControl = new WindowsFormsDemo.View.CreateOffer();
this.panMain.Controls.Clear();
this.panMain.Controls.Add(myControl);
}
User Control Code...
internal delegate void CreateOfferDelegate();
internal event CreateOfferDelegate CreateOffer;
public UserControl1()
{
InitializeComponent();
}
private void btnCreateOffer_Click(object sender, EventArgs e)
{
CreateOffer();
}

Show Tooltip programatically on a control inheriting from UserControl

I have a custom control inheriting from the UserControl class. It has got a ToolTip property but I need to show it when the mouse is dragged over it.
The Tooltip.Show method expects the second argument of type Control. I'm not sure how to with it.
Any ideas/help appreciated.
SetToolTip() only needs to be called once
class Foo : Form {
ToolTip tooltip = new ToolTip();
public Foo(){
tooltip.SetToolTip(this, "This is a tooltip!");
foreach(Control ctrl in this.Controls) {
tooltip.SetToolTip(ctrl, "This is a tooltip!");
}
}
}
Instantiate your tooltip in constructor and show it on mouse hover event.
Taken from Joseph's answer in stackoverflow
public ToolTip tT { get; set; }
public ClassConstructor()
{
tT = new ToolTip();
}
private void MyControl_MouseHover(object sender, EventArgs e)
{
tT.Show("Why So Many Times?", this);
}
Hope it helps.
I needed this myself, and found the partial solution offered above could be improved upon.
Basically, you need to set the MouseHover event for all applicable child controls to the MouseHover of the parent UserControl.
this can be done with code as below in the MyUserControl class constructor:
class MyUserControl:UserControl
{
string strTooltip;
public ToolTip toolTip
{
get;
set;
}
public MyUserControl()
{
toolTip = new ToolTip();
foreach(Control ctrl in this.Controls)
{
ctrl.MouseHover += new EventHandler(MyUserControl_MouseHover);
ctrl.MouseLeave += new EventHandler(MyUserControl_MouseLeave);
}
}
void MyUserControl_MouseLeave(object sender, EventArgs e)
{
toolTip.Hide(this);
}
void MyUserControl_MouseHover(object sender, EventArgs e)
{
toolTip.Show(strToolTip, this, PointToClient(MousePosition));
}
}
Note that we are using the PointToClient(MousePosition) to position the tooltip where the usercontrol is located.
Otherwise, sometimes, it can cause the tooltip to get displayed at a random location on the screen.
Hope this helps someone! :)
Just hit this problem myself today, and came up with this rather simple solution.
Add the following source file to your codebase somewhere (I put it in a file ToolTipEx.cs)
namespace System.Windows.Forms
{
public static class ToolTipEx
{
private static void SetTipRecurse(ToolTip toolTip, Control control, string tip)
{
toolTip.SetToolTip(control, tip);
foreach (Control child in control.Controls)
SetTipRecurse(toolTip, child, tip);
}
public static void SetTooltip(this ToolTip toolTip, UserControl control, string tip)
{
SetTipRecurse(toolTip, control, tip);
}
}
}
If it is in another DLL, make sure the DLL is referenced.
Then all you have to do is make the normal call to toolTip.SetToolTip(myControl, "some tip"); and the compiler will take care of the rest for you.
Because the function essentially extends the ToolTip.SetToolTip() method to one having the signature
ToolTip(UserControl control, string tip);
which is higher up in the hierachy than the original
ToolTip(Control control, string tip);
When we are dealing with a UserControl, it will be called instead of the original.
The new method does a simple recursive call to give all sub controls then same tool tip as the parent control.
This code assumes that the UserControl will not have other controls added to it after the call to SetToolTip is made.

Enabled button in a form through access control [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Get access to parent control from user control - C#
I have btnMessage on my form Main, and I also have user control (uc).
When I click btnMessage, it opens the uc and also makes btnMessage.enabled = false. In uc, there's a button that's called btnExecute.
What I want is that when I click on btnExecute in uc, btnMessage in Main form will be disabled. How I can do this?
Here's the update code :
I'm using function in main.cs
public Main()
{
InitializeComponent();
formFunctionPointer += new functioncall(buttonHideorEnabled);
ucMessageTarget.userFunctionPointer = formFunctionPointer;
}
public delegate void functioncall(bool _status);
private event functioncall formFunctionPointer;
public void buttonHideorEnabled(bool _status)
{
btnMessageTarget.Enabled = _status;
}
and in uc.cs :
public static string agentName = UtilitiesToolkit.agentMessageTarget;
public static string strn;
public UcMessageTarget(string str)
{
InitializeComponent();
strn = str;
}
public Delegate userControlPointer;
public Delegate userFunctionPointer;
private void btnExecute_Click(object sender, EventArgs e)
{
btnExecute.enabled = false;
userFunctionPointer.DynamicInvoke(false);
//I want btnMessage in Main form also disabled, please tell me how
}
but, still, didn't work. when I compile, I have error in main, in this line :
public Main()
{
InitializeComponent();
formFunctionPointer += new functioncall(buttonHideorEnabled);
ucMessageTarget.userFunctionPointer = formFunctionPointer;
}
said, that
object reference is not set to an instance of object (in
ucMessageTarget.userFunctionPointer = formFunctionPointer;).
please help.
You can programmatically subscribe to event handlers in the code-behind, so add one to the "parent" form for the "child" form's button:
uc.btnExecute.Click += new EventHandler(name_of_method_to_handle_click_event);
The only requirement is that the control be public so that the parent form can access it.
What I would rather do is raise an event from the user control, which the main form listens to, and then disable the button in this event handler.
Something like User Control Events in VB and C#
This would avoid the user control having to "know" anything about the caller (parent form).
Search a little on SO, you will find a lot of examples for raising events from user controls.

How to pass textbox data between two forms?

How to send textbox value to textbox between two forms without Show()/ShowDialog() by button?
I want to textBox will get value without open form.
To access the textbox data you need to use: textBox1.Text
a form is an object so you can define a method that updates the text box value (you can expose the textbox itself with a public accessor)
To pass information from a parent from to a child form you should create a property on the child form for the data it needs to receive and then have the parent form set that property (for example, on button click).
To have a child form send data to a parent form the child form should create a property (it only needs to be a getter) with the data it wants to send to the parent form. It should then create an event (or use an existing Form event) which the parent can subscribe to.
An example:
namespace PassingDataExample
{
public partial class ParentForm : Form
{
public ParentForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child = new ChildForm();
child.DataFromParent = "hello world";
child.FormSubmitted += (sender2, arg) =>
{
child.Close();
string dataFromChild = child.DataFromChild;
};
child.Show();
}
}
}
namespace PassingDataExample
{
public partial class ChildForm : Form
{
public ChildForm()
{
InitializeComponent();
}
public string DataFromParent { get; set; }
public string DataFromChild { get; private set; }
public event EventHandler FormSubmitted;
private void button1_Click(object sender, EventArgs e)
{
DataFromChild = "Hi there!";
if (FormSubmitted != null)
FormSubmitted(this, null);
}
}
}
I don't know what exactly you mean by saying "without Show()/ShowDialog()", but that is not relevant anyway or I'll just assume here further that you have both windows open (doesn't matter how you accomplished that).
You would like to avoid much coupling between two forms, especially not implementation details like a textbox etc. You could work with delegates and events to trigger the "sending" of data between your two forms. You can then easily pass event data and your subscribed other form (or any other object as a matter of fact) doesn't know the exact implementation details of your form, it only knows the data it will receive through the delegate (event). I am not going to post all code here, because it is already nicely explained at following URL: http://www.codeproject.com/Articles/17371/Passing-Data-between-Windows-Forms .

Categories