I am having a WinForms control, inside that I have a TableLayoutPanel which holds multiple ElementHosts and each ElementHost contains a WPF control.
Everything works fine except when the size of controls is bigger then window and ScrollBar is there; when I scroll down, the controls get rendered distorted, like this -
On maximizing the window or re-sizing it, controls render properly
(reducing the size such that controls go out of visible area and then increase the size again to bring them back in visible area)
This doesn't happen with WinForms control in the same window just the WPF ones; any idea why this is happening and any solution for this?
this.Loaded += delegate
{
var source = PresentationSource.FromVisual(this);
var hwndTarget = source.CompositionTarget as HwndTarget;
if (hwndTarget != null)
{
hwndTarget.RenderMode = RenderMode.SoftwareOnly;
}
};
Try using that in the wpf control you are hosting. This is a known rendering issue of the the wpf controls that are hosted in win forms. Changing the rendering mode to software only will solve the problem.
I had a similar problem and solved forcing a refresh of the ElmenetHost in the scroll event of the TableLayoutPanel
Ok, this is gonna sound like total B.S. but it worked for me: in the Load event of your form, resize the form.
public class MyForm : Form
{
public MyForm()
{
Load += (o, e) => { Width -=1; Width +=1; };
}
}
After the form has been resized, I could not force a display issue.
Related
I have been working on a WPF application, and my application freezes as I Navigate from one window to another, The first window is for Login and the second window is the main window where work is carried out (the application is a form based application where Data is Written to and from a Database like MySQL)
2nd Window Operations
In the second window, I have created a Menu by placing Icons in a List and then Handling their click events to navigate to a page
These Pages are not the UI Element 'Page' but are Usercontrols I refer to them by Pages for Simplicity, and these usercontrols are added to the grid by grid.children.Add(UsercontrolName);. . . . . . This part of adding usercontrols as you can see is done in code behind(C#) and not by XAML
Click Event Handling
All i do is I simply shift the visibilty of a Usercontrol, so for example an icon that is related to a say Usercontrol A, that usercontrols visibity is set to visible and all other usercontrols visibilty is set to Collapsed, by default all usercontrols Visibilty is set to Collapsed
The Problem
What I do not Understand is what is causing this Lag or Freeze or even how to find or figure this out, I understand that WPF is an STA and UI elements such as a Grid/usercontrols should be run on the main thread , so if we Used Dispatcher to resume to the Main thread the UI wont freeze but it would Still take time to load, and I want to stop this delay
Although Contradictory I still think its the Adding of Usercontrols to the Grid is causing slow speeds, bcz these Usercontrols have numerous UI elements that I am using from a library called MaterialDesigninXAML, its a form based application so have like 8 Usercontrols all of them with textboxes and Imageboxes and buttons etc, and adding these Usercontrols at once is causing the Overhead
And I am stuck at this Delay / Freeze of the UI
The code below is a ditto example of my original code, I posted the example bcz my code is lengthier with the same problem
this is the part of the code that lags
Dispatcher.InvokeAsync(() =>
{
UserControl usc;
usc = new Y1();
usc.Tag = "Memeber";
no.Children.Add(usc);
Y4 usc2 = new Y4();
usc2.Tag = "CheckBoxList";
no.Children.Add(usc2);
Y5 usc3 = new Y5();
usc3.Tag = "Reports";
no.Children.Add(usc3);
ShowUserContro("Memeber");
}
);
private void ShowUserContro(string v)
{
foreach (UIElement item in no.Children)
{
if (item is UserControl)
{
UserControl x = (UserControl)item;
if (x.Tag != null)
{
if (x.Tag.ToString().ToUpper() == v.ToUpper())
{
x.Visibility = Visibility.Visible;
}
else
{
x.Visibility = Visibility.Collapsed;
}
}
}
}
}
private void ListViewMenu_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ShowUserContro((((ListViewItem)((ListView)sender).SelectedItem).Name));
}
I have a WinForms application. Each form and user control sets up its tooltips as follows:
// in the control constructor
var toolTip = new ToolTip();
this.Disposed += (o, e) => toolTip.Dispose();
toolTip.SetToolTip(this.someButton, "...");
toolTip.SetToolTip(this.someCheckBox, "...");
...
However, the tooltips don't appear when I hover over the controls. Is this an appropriate way to use tooltips? Is there something that could be happening in another part of the application (e. g. listening to some event) that would stop tooltips from working?
Note that tooltips on my outer form's toolstrip buttons (which are configured via the button's tooltip property) do work as expected.
EDIT:
I've observed this more and I've noticed that sometimes the tooltip does show up, it is just extremely "flaky". Basically, sometimes when I mouse over a control it will show up very briefly and then flicker away. I can get it to show manually with .Show() and a long AutoPopDelay, but then it never disappears!
Your code seems ok to me. I couldnt find anything wrong in your code. But, it could be failed only when control is disabled. BTW, you can try another method like this. but, i would not like to suggest you to show the tooltip like this.
private void someButton_MouseEnter(...)
{
toolTip.Show("Tooltip text goes here", (Button)sender);
}
You can also assign the location where tooltip should be displayed in .Show() method. there are some overloaded function that you can use. Read the msdn for more information about ToolTip.Show() method.
I faced similar issue when my tooltip was not showing up over the RichTextBox once in about 3-5 times it normally should. Even forcing it to show explicitly with toolTip.Show didn't help. Until I changed to the way mentioned by Shell - you have to tell where you want your tooltip to appear:
'Dim pnt As Point
pnt = control.PointToClient(Cursor.Position)
pnt.X += 10 ' Give a little offset
pnt.Y += 10 ' so tooltip will look neat
toolTip.Show(text, control, pnt)
This way my tooltip always appears when and where expected.
Good luck!
I wrote the following method to "propagate" ToolTips from parent controls (that have a tool tip set) to its child controls (unless they have their own overriding ToolTip).
It's designed to be dropped into the form or control you're starting with, but it could also just be turned into a static method where the "parent" argument is required.
/// <summary>Setting a toolTip on a custom control unfortunately doesn't set it on child
/// controls within its drawing area. This is a workaround for that.</summary>
private void PropagateToolTips(Control parent = null)
{
parent = parent ?? this;
string toolTip = toolTip1.GetToolTip(parent);
if (toolTip == "")
toolTip = null;
foreach (Control child in parent.Controls)
{
// If the parent has a toolTip, and the child control does not
// have its own toolTip set - set it to match the parent toolTip.
if (toolTip != null && String.IsNullOrEmpty(toolTip1.GetToolTip(child)))
toolTip1.SetToolTip(child, toolTip);
// Recurse on the child control
PropagateToolTips(child);
}
}
Note that the behaviour is undefined if you're using more than one ToolTip instance to manage parent and child control toolTips.
We're running into a small problem here which really annoys us. Let me quickly explain what we're doing:
We're creating a Windows Form, save it as .DLL and load it a MDIContainer. Seems fine, works fine, except that, if we're using a Panel as component in our Form, it changes the size.
Before:
After (in MDIContainer):
(NOTE THE PANEL!).
We're guessing that it's because of our Custom MDI Container. This is the code of our MDI Container:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace NAMESPACE.Forms
{
class MdiClientPanel : Panel
{
private Form mdiForm;
private MdiClient ctlClient = new MdiClient();
public MdiClientPanel()
{
this.ctlClient.BackColor = Color.LightGray;
base.Controls.Add(this.ctlClient);
}
public Form MdiForm
{
get
{
if (this.mdiForm == null)
{
this.mdiForm = new Form();
System.Reflection.FieldInfo field = typeof(Form).GetField("ctlClient", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
field.SetValue(this.mdiForm, this.ctlClient);
}
return this.mdiForm;
}
}
}
}
Is there any way we can fix this? Thanks for helping.
//Edit:
Added bounty, because we want to know why this is so. How you can reproduce it:
Copy our MDIClientPanel code inside a new class in a new project
Create a second form, put some Controls inside it.
Load the form inside the MDIClient Panel.
Compile and look how the Size of the second form is changing.
This can be fixed if you open the second form like this:
SecondForm Form = new SecondForm();
Form.MdiParent = this.MdiClientPanel.mdiForm;
Form.Size.Width += 35; //THIS PART WILL FIX
Form.Size.Height += 20; //THIS PART WILL FIX IT
Form.Show();
But there is no way this is the only solution is it's kinda fishy...
The reason why this is happening, is because the boundries of the panel are not set.
You should be able to over come this by one of the following ways:
1 - Dock the panel;
var x = new MdiClientPanel{Dock = DockStyle.Fill};
Controls.Add(x); //Add the control to the form
2 - Anchor the panel to all corners;
x.Anchor = AnchorStyles.Top;
x.Anchor = AnchorStyles.Right;
x.Anchor = AnchorStyles.Left;
x.Anchor = AnchorStyles.Bottom;
I was able to reproduce this error and correct it using the above method(s).
Anchoring (before):
Anchoring (after - resizing parent):
Dock (before):
Dock (after - resize parent):
Hope this helps.
You have a fixed width and height at design time, it somehow does not follow your form to resize itself.
normally what we do is always to use a table layout panel (if there are more than one visible controls on the same form) and for each control, set the Dock to DockStyle.Fill. if there is only one control in the form, set the control itself to fill in to the form or the parent control (such as a tableLayoutPanel), and then set the following at either Design or behind-code:
pnl.Dock = DockStyle.Fill;
if you do want to leave some pace beside some controls, use TableLayoutPanel to have extra columns/rows with width (either fixed or in percentage). and then place the controls (like your panel) inside the cell you choose and set dockstyle to fill.
Consider anchoring the panel in your form. This will ensure that the panel will have equal space around it, regardless of the size of its parent form. Generally I prefer this over DockStyle.Fill.
When using the form as an MDI child, you really want to delegate control over its size to its MDI container. Just make sure your MDI child handles it nicely.
Let's just say that I have many controls on my Form, and when a User clicks on one of them, its height will expand. This means that, currently, when this clicked-control expands, other controls below it will become overlapped by the expanded control.
But what I want to happen, is for each Control below the expanded control to slide down, so that they are below the expanded control again.
I know how to handle sliding, but I just don't know how to make every control except for one move everytime a given control is moved.
Any help at all is greatly appreciated, thank you!
This is what I was thinking:
void newOrderReceived(object sender, EventArgs e)
{
foreach(Control OrderNotificationBox in OrdersPanel.Controls)
{
if(OrderNotificationBox is NotificationBox) // Checks to see if the control is a NotificationBox
{
// Add my code to slide controls down.
}
}
}
But... How do I know if the control is below the expanded control?
Is this how I should go about changing the location of all controls below the expanded control?
Edit: Just had a thought, to check to see if a NotificationBox is below the Expanded NotificationBox, see revised code below:
void newOrderReceived(object sender, EventArgs e)
{
foreach(Control OrderNotificationBox in OrdersPanel.Controls)
{
if(OrderNotificationBox is NotificationBox) // Checks to see if the control is a NotificationBox
{
if(OrderNotificationBox.Location.Y <= ExpandedNotificationBox.Location.Y + ExpandedNotificationBox.Size.Width)
{
// Add my code to slide controls down.
}
}
}
}
But would this be sufficient? Currently, this is working, so I guess I just answered my own question. But, isn't there a better way to do this? A more elegant/efficient way?
Here's a sample of how it should look:
FlowLayoutPanel provides you with dynamic layout where you can resize any control in it and all below controls will slide automatically. There are many strategies to using groups/columns of flow layout panels to be able to achieve the desired look for the whole form. Some googling will reveal some of these.
For instance in the form above, resizing the button1 control simply flows all the below controls to further down on the form. You can try that at the design time also. Drop the form a flow layout panel, drop 3-4 control in the container and start experimenting..
For each expandable content use Panel.
Dock your panels one under another (Use panel1.Dock = DockStyle.Top. For the very bottom panel use panel1.Dock = DockStyle.Fill).
Place your child controls inside of each expandable panel, set inner controls' Anchor properties accordingly.
When you expand one panel, the rest of the panels will adjust automatically. You don't need to code for this. You will only change Height of a panel that you currently expand.
What you need is some kind of 'ExplorerBar' functionality. There are several control libraries that offer that, and I found the article here on the CodeProject that has it for free.
In java swing I can insert panels into panels and so on, and not have to build a brand new window for every view of my applicaiton, or mess around removing and adding controls.
Theres a panel clas sin C# however I cant see any way of creating a 'panel form' or basically just a form in form designer thats a panel and its contents.
How do I do this then and work the way I did with java swing?
Usually i just dock different forms within eachother setting the IsMdiContainer Property to true on the parent window. Then i create subforms that i dock using the following function:
static class FormUtil
{
static public void showForm(Form sender, Control reciever)
{
sender.ControlBox = false;
sender.FormBorderStyle = FormBorderStyle.None;
sender.ShowInTaskbar = false;
sender.TopLevel = false;
sender.Visible = true;
sender.Dock = DockStyle.Fill;
reciever.Controls.Clear(); //clear panel first
reciever.Controls.Add(sender);
}
}
then whenever i need to dock a form inside a panel on the parents form i just do:
FormUtil.showForm(new SomeForm(), this.splitContainer1.Panel1);
This allows me to delegate some of the form creation to different designers. Works like a charm for me, love to hear if theres a better way of doing it.
Actually, you can use the panel control and set it's Dock property to Fill. That way, your panel will be the entire canvas of the form. Then, you can add child panels as needed either through code behind or through forms designer.
There's the concept of user controls which basicly provides you with a panel like designer surface , not to mention that you can create atomic forms (which can be reused) and register them as inheritable, that way you can provide inheritance too.