I somehow noticed, that while I'm creating a control in my application, it first appears as weird rectangle and then it "shrinks" to it's correct form.
First thing you'll see after creation
Correctly created object
My question is, why I first see the rectangle in top left corner and then it suddenly changes to it's correct form. It's like split second thing (I had to use Thread.Sleep 'cos it's impossible to screenshot it), but my eyes can still see this and I'm really triggered when it's happening.
This is the code, where I'm creating the control:
var label = new Label
{
AutoSize = true,
TextAlign = ContentAlignment.MiddleLeft,
Font = new Font("Courier New", 9F, FontStyle.Regular,
GraphicsUnit.Point, 238),
Text = keyword,
Margin = new Padding(0, 6, 25, 3),
Padding = new Padding(0, 3, 0, 0)
};
var button = new Button
{
BackgroundImage = Image.FromFile("../../../Images/cross_200x200.png"),
BackgroundImageLayout = ImageLayout.Stretch,
Dock = DockStyle.Right,
Width = 21,
Height = 21,
FlatStyle = FlatStyle.Flat,
};
button.FlatAppearance.BorderSize = 0;
var pan = new Panel
{
AutoSize = true,
Padding = new Padding(0, 0, 1, 1),
BackColor = Color.PowderBlue,
BorderStyle = BorderStyle.FixedSingle,
Tag = keyword
};
button.Click += delegate
{
_keywords.Remove(pan.Controls.OfType<Label>().First().Text);
pan.Dispose();
StatusLabel.Text = $#"Removed {keyword}";
};
pan.Controls.Add(label);
pan.Controls.Add(button);
FlowLayoutPanelMain.Controls.Add(pan);
Everytime a "keyword" is added to FlowLayoutPanel control, at first it's a rectangle in top left corner and immediately after that it's fine.
With help from a friend of mine, we figured out, that this is happening due to Windows Forms old technology (It's probably not happening in .NET Core's WPF) and it's inability of creating controls at runtime. So, the offered solution for this seems to be just .Hide() the control, .Add() it to the FlowLayoutPanel and then simply .Show() it back, now my eyes will be satisfied.
...
pan.Hide();
FlowLayoutPanelMain.Controls.Add(pan);
pan.Show();
...
Try to remove AutoSize property and assign a new Size() to the panel
AutoSize = false,
Worked for me
Related
Can anyone help me to understand the usefulness of the Margin property?
Using the simple scenario below, I can't see how it's useful
SET UP
I created a simple app to test this:
Created a new WinForms app from the template
Opened Form1 in the designer
Added a 'Panel' (called Panel1) onto Form1 from the toolbox, with:
Dock = Fill;
Size.Width = 800px;
Size.Height = 450px`;
Added two child 'Panels' onto Panel1
Panel2 has Dock = Left
Panel3 has Dock = Right
Both Panel2 and Panel3 have Size.Width = 400px, Size.Height = 450px (so Panel2 and Panel3 effectively split Panel1 into 2 down the middle)
WHY THE PADDING PROPERTY MAKES SENSE TO ME:
The usefulness of Padding is obvious in the designer - it enforces space between the border of the parent (Panel1) and its contents (Panel2 and Panel3)).
So if I set Panel1.Padding.All = 10, then the Size.Height of both Panel2 and Panel3 is forced to decrease (by 20px) to 430px.
Their Size.Width stays the same (they just become overlapped).
Winforms then prevents the Size.Height of Panel2/Panel3 from being increased above 430px, as this would encroach into the padding space of Panel1.
This all makes sense to me
WHY THE MARGIN PROPERTY DOES NOT MAKE SENSE TO ME
Margin is the space around the border of an element - it keeps other elements from getting too close to the element you're setting the Margin on.
So I thought that if I set Margin.Right (on Panel2) to 10px, this would force the Size.Width of Panel3 to decrease (so that it wasn't encroaching on the margin of Panel2).
Instead, setting this right margin appears to have no visible impact on the form?
The Margin property is primarily used by the visual designer and reflected with "snaplines" when positioning controls on the design surface.
See this walkthrough from Microsoft.
One way to think about it (generally) is that Margin is something that happens outside the control whereas Padding is something that happens inside. Also, the "total" effect can be the result of the parent's padding added to the margin of the child control.
The MainForm has padding of 25 (shown in blue) and contains a FlowLayoutPanel set to Dock.Fill. To avoid confusion, the padding and margin of the flow layout panel is set to 0.
The 6 child controls of the flow layout panel set their own left-top margin to 10 and bottom margin to 40. At the top left and the bottom of each child the BackColor of LightSalmon shows through. There is a total of 50 from the bottom of one child to the top of the next one below. Each child control also sets its padding value to 15 which will apply on all four sides of the buttons it contains.
The padding and margin of Button are also set to 0. The the button is auto-sized and centered because it is anchored on all sides.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Main form Padding in light blue
BackColor = Color.LightSkyBlue;
Padding = new Padding(25);
flowLayoutPanel.BackColor = Color.LightSalmon;
// Set these to 0 and let the individual controls
// manage the padding and margins.
flowLayoutPanel.Margin = new Padding(all: 0);
flowLayoutPanel.Padding = new Padding(all: 0);
for (int i = 1; i <= 6; i++)
{
var panel = new TableLayoutPanel
{
Name = $"panel{i}",
Size = new Size(200, 100),
// Margin 'outside' the panel will show in Light Salmon.
// This will space the panels inside the FlowLayoutPanel
Margin = new Padding(left: 10, top: 10, right: 0, bottom: 40),
// The button inside this panel will have Padding around it.
Padding = new Padding(all: 15),
BackColor = Color.LightGreen,
BackgroundImage = new Bitmap(
Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Images",
"back-image.png"
)),
BackgroundImageLayout = ImageLayout.Stretch,
};
// Add button to internal panel
var button = new Button
{
Name = $"button{i}",
Text = $"Button {(char)(64 + i)}",
BackColor = Color.DarkSeaGreen,
ForeColor = Color.WhiteSmoke,
// By anchoring the button, it will autosize
// respecting the Padding of its parent.
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom,
Margin = new Padding(all: 0),
Padding = new Padding(all: 0),
};
panel.Controls.Add(button);
flowLayoutPanel.Controls.Add(panel);
}
}
}
My code looks like this:
TextSymbol ts = new TextSymbol()
{
Font = new SymbolFont("Arial", 18),
BackgroundColor = Color.FromArgb(160, 255, 255, 255),
HorizontalTextAlignment = HorizontalTextAlignment.Center,
VerticalTextAlignment = VerticalTextAlignment.Baseline,
Text = icon.description,
XOffset = 0,
YOffset = -icon.height
};
var pointGraphic = new Graphic(GeometryEngine.Project(new MapPoint(icon.Longitude, icon.Latitude, 100, wgs84), MyViewBase.SpatialReference), ts);
The text symbol shows up as expected on the MapView, but the SceneView there is no background box and the text is not centered under the appropriate lat/long.
Is this capability not available for SceneView? If not, how can I do this?
Unfortunately text background is not supported in the first v100 release. We hope to have it in the next update, but it's not be in yet, so I can't with 100% certainty promise it yet.
We do however support outline color, so perhaps you can use that instead?
I have a wpf user control , inside it i have put a canvas named VisualFeedback , now programmatically i add a eclipse using :
Ellipse ellipse = new Ellipse
{
Fill = new SolidColorBrush(Colors.Red),
Width = 5,
Height = 5,
Opacity = 1,
Margin = new Thickness(10, 10, 0, 0)
};
VisualFeedback.Children.Add(ellipse);
But it does not show up in the canvas of usercontrol which is in the mainwindows of the application .
Your code works for me - you're sure that you're not just missing it? - it's quite small.
Tricky one to explain this. I have a custom built properties grid. The left hand column has the property labels. Sometimes depending on the property, I want a little elipsis button to show the user that they can launch a dialog. I want the buttons to be inline vertically to make the UI look neat. The labels vary in width depending on the name of the property "onEnterPressed" or "upLink" for example.
If I add the elipses button alone and use a margin like so ...
elipsisButton.Margin = new Thickness(135, 0, 0, 0);
135 from the left is exactly where I want to place the button.
I was hoping to be able to do something like
Label newLabel = new System.Windows.Controls.Label();
newLabel.Content = anInfo;
aPanel.Children.Add(newLabel);
elipsisButton.Margin = new Thickness(135 - newLabel.Width, 0, 0, 0);
It would appear however, that the label doesn't get a width until it's been rendered on screen so I can't find out what size margin to add to my elipsis button. Any ideas?
You can call the Measure() method in order to ask the control the size it needs to be displayed:
var l = new Label() { Content = "Hello" };
l.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Size s = l.DesiredSize;
And then use the value of the DesiredSize property.
My Windows Forms application has a MenuStrip and some of the menu items (ToolStripMenuItem) have an icon (setting the ToolStripMenuItem.Image property).
When the RenderMode property of the MenuStrip is set to ToolStripRenderMode.System, the checkmark doesn't display when the Checked or CheckOnClick property is true and the menu item has an icon.
It does display when i switch the MenuStrip.RenderMode property to ToolStripRenderMode.Professional or ToolStripRenderMode.RenderManagerMode.
Unfortunately, this is a problem because my app requires:
A ProgressBar in marquee mode, so Application.EnableVisualStyles() is required to get this to work.
The app requires a "flat" visual style, which i accomplished by leaving out the call to Application.EnableVisualStyles() and leaving the default ToolStripRenderMode.RenderManagerMode on the MenuStrip. But then i can't get my marquee ProgressBar!
Setting the RenderMode to ToolStripRenderMode.System solves the look and feel requirement, but takes away the ability to have checked menu items w/icons.
Is there any way to satisfy all my requirements? Am i missing something? Thanks for looking.
Wow, i stumped SO! Now i know i must be working on some serious code.
Anyway, the answer is: implement your own ToolStripRenderer by creating a class that inherits from ToolStripSystemRenderer.
Override the methods that draw the items with your own code. Here's what i was looking for specifically that draws the checked item. It draws a check if there's no image for the ToolStripMenuItem.
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
{
base.OnRenderItemCheck(e);
if (e.Item.Selected)
{
Rectangle rect = new Rectangle(3, 1, 20, 20);
Rectangle rect2 = new Rectangle(4, 2, 18, 18);
SolidBrush b = new SolidBrush(Color.FromArgb(49, 106, 197));
SolidBrush b2 = new SolidBrush(Color.Orange);
e.Graphics.FillRectangle(b, rect);
e.Graphics.FillRectangle(b2, rect2);
e.Graphics.DrawImage(e.Image, new Point(5, 3));
}
else
{
Rectangle rect = new Rectangle(3, 1, 20, 20);
Rectangle rect2 = new Rectangle(4, 2, 18, 18);
SolidBrush b = new SolidBrush(Color.FromArgb(49, 106, 197));
SolidBrush b2 = new SolidBrush(Color.Orange);
e.Graphics.FillRectangle(b, rect);
e.Graphics.FillRectangle(b2, rect2);
e.Graphics.DrawImage(e.Image, new Point(5, 3));
}
}
I did also come across a simpler alternative:
You can simply put your menu items into a ContextMenuStrip and then assign it to the DropDown property of the DropDownButton.
Hope this helps anyone out there who doesn't fancy overriding the Paint method.