In MAUI apps, how can I completely disable window resize and fix the width and height to something like 200px?
Visual Studio automatically generates this code:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
The Height and Width properties are readonly. I have found a RequestedWidth but it doesn't change anything. When I try to change the base class to something else, I get an error saying that is not authorized.
I don't really care if fixing the size does not make sense in Android or similar operating systems, it is important in Windows. So is there any way to do this?
For windows, after the font settings, you can add this code to your MauiProgram.cs file. This will disable resize. Optionally you can change border and title bar visibility too. If you don't disable title bar and border, buttons in the upper right corner of the window will be still visible and users still be able to switch your app to full screen mode. I recommend you to disable them too. Finally if you want to disable title bar you should set ExtendsContentIntoTitleBar property to false too. If you don't, you'll still see half the title bar.
#if WINDOWS
builder.ConfigureLifecycleEvents(events =>
{
events.AddWindows(windowsLifecycleBuilder =>
{
windowsLifecycleBuilder.OnWindowCreated(window =>
{
window.ExtendsContentIntoTitleBar = false;
var handle = WinRT.Interop.WindowNative.GetWindowHandle(window);
var id = Win32Interop.GetWindowIdFromWindow(handle);
var appWindow = AppWindow.GetFromWindowId(id);
switch (appWindow.Presenter)
{
case OverlappedPresenter overlappedPresenter:
overlappedPresenter.SetBorderAndTitleBar(false, false);
overlappedPresenter.IsResizable = false;
break;
}
});
});
});
#endif
Now your Window size is fixed but it's height & width still at default value. You should add this code to your MainPage.xaml.cs;
protected override void OnAppearing()
{
base.OnAppearing();
double height = 600;
double width = 365;
Window.Height = height;
Window.Width = width;
}
Related
I'm working on a Excel add-in project that will require me to procedurally generate some controls in a windows task pane. While experimenting, I ran into an issue where this button keeps having its width set to 0, and I don't understand why.
If I don't use any anchoring or docking then the button shows up, but at its default width and height. I am trying to get it to span the width of the layout panel, and it was my understanding you could accomplish this by using AnchorStyles Left and Right, or with DockStyle Fill. However, as soon as I add these properties the width gets set to 0 (as seen from the debugger). I checked the width of the root control (this) and the button's parent control FlowLayoutPanel, and they are both the default non-zero size.
What am I doing wrong?
public MyUserControl()
{
FlowPanel = new FlowLayoutPanel
{
Name = "My Flow Panel",
TabIndex = 0,
FlowDirection = FlowDirection.TopDown,
};
Button button1 = new Button
{
Name = "button1",
Text = this.Width.ToString(),
FlatStyle = FlatStyle.Flat,
Padding = new Padding
{
Left = 10
},
Parent = FlowPanel,
Anchor = (AnchorStyles.Left | AnchorStyles.Right)
};
FlowPanel.Controls.Add(button1);
this.Controls.Add(FlowPanel);
}
You can't anchor like that in FlowLayoutPanels. Instead, subscribe to the SizeChanged event and modify the button width there. You'll probably also need to set the width when you create the button, so below I've just created a method you can call from both places.
FlowPanel.SizeChanged += new System.EventHandler(this.FlowPanel_SizeChanged);
private void FlowPanel_SizeChanged(object sender, EventArgs e)
{
SetButtonWidth();
}
void SetButtonWidth()
{
button1.Width = FlowPanel.Width - FlowPanel.Padding.Horizontal - button1.Margin.Horizontal;
}
For a project, I have to make a Windows Forms Application that makes a Mandelbrotfigure. Now i want to add a vertical separator between the UI on the left and the Figure on the right (See Picture). Any idea on how to do that?
This is too late to answer this, but for the ease of anyone who ends up here searching:
As Line control deprecated, just use a Label control with AutoSize = false and Size = 1,xx with any BackColor you like your line to be.
Replace xx in the Size with actual height.
public class VertSep : Control
{
private Color lineColor;
private Pen linePen;
public VertSep()
{
this.LineColor = Color.LightGray;
SetStyle( ControlStyles.SupportsTransparentBackColor, true );
}
public Color LineColor
{
get
{
return this.lineColor;
}
set
{
this.lineColor = value;
this.linePen = new Pen( this.lineColor, 1 );
this.linePen.Alignment = PenAlignment.Inset;
Refresh();
}
}
protected override void Dispose( bool disposing )
{
if( disposing && this.linePen != null )
{
this.linePen.Dispose();
this.linePen = null;
}
base.Dispose( disposing );
}
protected override void OnPaint( PaintEventArgs e )
{
var g = e.Graphics;
int x = this.Width / 2;
g.DrawLine( linePen, x, 0, x, this.Height );
base.OnPaint( e );
}
}
You'll have to move all your contents inside a SplitContainer. This container contains two panels and a divider. You'll have to place the controls on one side and the image on the other panel.
In your particular case you'll probably have to start over.
Using the designer you should set the SplitContainer's Dock property on Fill. You can move the divider by selecting it and dragging (this is only possible if you have the SplitContainer selected). Once the divider is in the right place, it might be wise to set the FixedPanel property to the left panel as you probably don't want this panel to grow when maximizing.
It's still possible to move the divider in the application as long as the property IsSplitterFixed is set to False.
I wrote a custom Separator control just for this purpose. You can install it via the NuGet Package Manager Console:
Install-Package ALMSTWKND -Version 1.0.0
Just drag and drop it onto your Form from the Toolbox after installation.
When I add my UserControls to a FlowLayoutPanel, they display properly. When I change the Dock or Anchor properties on the UserControls before adding them, they are still added but do not render.
According to "How to: Anchor and Dock Child Controls" this should be possible.
I can tell that the controls are added (despite not drawing) because adding enough of them causes a vertical scrollbar to appear.
Setting the "Dock" property of the UserControls to "Left" or "None" will cause them to render, but none of the other options.
Setting the "Anchor" property on the UserControls to anything but Top | Left does not render.
Setting the dock before or after adding the control makes no difference (Add, Dock vs. Dock, Add).
The FlowLayoutPanel is itself is docked (Fill), has FlowDirection set to TopDown, has WrapContents set to false, has AutoScroll set to true, and is otherwise default.
I am using .NET 3.5.
In answer to a comment, the two commented lines are the locations I tried to change the dock. The second spot definitely makes more sense, but I tried the other because it couldn't hurt.
public void CreateObjectControl( object o )
{
ObjectControl oc = new ObjectControl();
oc.MyObject = o;
//This was a spot I mentioned:
//oc.Dock = DockStyle.Fill;
ObjectDictionary.Add( o, oc );
flowLayoutPanel1.Controls.Add( oc );
//This is the other spot I mentioned:
oc.Dock = DockStyle.Fill;
}
try using SuspendLayout and Resumelayout function for the controls before making any amendments which need rendering for proper viewing.
You could see the code from Designer.cs for that particular control
Syntax
control.SuspendLayout();
{Your code for designer amendments}
control.resumeaLayout();
I think I may have found a workaround (read: dirty trick) ... this answer helped to point me in the right direction. Here's an excerpt from the MS article that you also linked to:
For vertical flow directions, the FlowLayoutPanel control calculates the width of an implied column from the widest child control in the column. All other controls in this column with Anchor or Dock properties are aligned or stretched to fit this implied column.
The behavior works in a similar way for horizontal flow directions. The FlowLayoutPanel control calculates the height of an implied row from the tallest child control in the row, and all docked or anchored child controls in this row are aligned or sized to fit the implied row.
This page does not specifically mention that you can't Dock/Anchor the tallest/widest control. But as this control defines the layout behaviour of the FlowLayoutPanel, and thus influences the way all other sibling controls are displayed, it is well possible that Dock and Anchor don't work properly for that 'master control'. Even though I can't find any official documentation regarding that, I believe it to be the case.
So, which options do we have? At runtime, we could add a panel control of height 0 and width of the FlowLayoutPanel client area before you add your usercontrol. You can even set that panel's visibility to false. Subscribing to some Resize/Layout events of the FlowLayoutPanel to keep that panel's size will to the trick. But this does not play nicely at design time. The events won't fire and thus you can't really design the surface the way you want it to look.
I'd prefer a solution that "just works" at design time as well. So, here's an attempt at an "invisible" control that I put together, to fix the controls resizing to zero width if no other control is present. Dropping this as first control onto the FlowLayoutPanel at design time seems to provide the desired effect, and any control subsequently placed on the FlowLayoutPanel is anchorable to the right without shrinking to zero width. The only problem is that, once this invisible control is there, it seems I can't remove it anymore via the IDE. It probably needs some special treatment using a ControlDesigner to achieve that. It can still be removed in the form's designer code though.
This control, once placed onto the FlowLayoutPanel, will listen for resize events of it's parent control, and resize itself according to the ClientSize of the parent control. Use with caution, as this may contain pitfalls that didn't occur to me during the few hours I played with this. For example, I didn't try placing controls that were wider than the FlowLayoutPanel's client area.
As a side note, what will still fail is trying to anchor to the bottom, but that wasn't part of the question ;-)
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
namespace ControlTest
{
public sealed class InvisibleControl : Control
{
public InvisibleControl()
{
TabStop = false;
}
#region public interface
// Reduce the temptation ...
public new AnchorStyles Anchor
{
get { return base.Anchor; }
set { base.Anchor = AnchorStyles.None; }
}
public new DockStyle Dock
{
get { return base.Dock; }
set { base.Dock = DockStyle.None; }
}
// We don't ever want to move away from (0,0)
public new Point Location
{
get { return base.Location; }
set { base.Location = Point.Empty; }
}
// Horizontal or vertical orientation?
private Orientation _orientation = Orientation.Horizontal;
[DefaultValue(typeof(Orientation), "Horizontal")]
public Orientation Orientation
{
get { return _orientation; }
set
{
if (_orientation == value) return;
_orientation = value;
ChangeSize();
}
}
#endregion
#region overrides of default behaviour
// We don't want any margin around us
protected override Padding DefaultMargin => Padding.Empty;
// Clean up parent references
protected override void Dispose(bool disposing)
{
if (disposing)
SetParent(null);
base.Dispose(disposing);
}
// This seems to be needed for IDE support, as OnParentChanged does not seem
// to fire if the control is dropped onto a surface for the first time
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
ChangeSize();
}
// Make sure we don't inadvertantly paint anything
protected override void OnPaint(PaintEventArgs e) { }
protected override void OnPaintBackground(PaintEventArgs pevent) { }
// If the parent changes, we need to:
// A) Unsubscribe from the previous parent's Resize event, if applicable
// B) Subscribe to the new parent's Resize event
// C) Resize our control according to the new parent dimensions
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
// Perform A+B
SetParent(Parent);
// Perform C
ChangeSize();
}
// We don't really want to be resized, so deal with it
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
ChangeSize();
}
#endregion
#region private stuff
// Make this a default handler signature with optional params, so that this can
// directly subscribe to the parent resize event, but also be called without parameters
private void ChangeSize(object sender = null, EventArgs e = null)
{
Rectangle client = Parent?.ClientRectangle ?? new Rectangle(0, 0, 10, 10);
Size proposedSize = _orientation == Orientation.Horizontal
? new Size(client.Width, 0)
: new Size(0, client.Height);
if (!Size.Equals(proposedSize)) Size = proposedSize;
}
// Handles reparenting
private Control boundParent;
private void SetParent(Control parent)
{
if (boundParent != null)
boundParent.Resize -= ChangeSize;
boundParent = parent;
if (boundParent != null)
boundParent.Resize += ChangeSize;
}
#endregion
}
}
I've got a StatusStrip with a single ToolStripStatusLabel, Spring=true and a background color for notifications.
The problem is that there's an ugly gray square on the right side of the status strip. After fiddling for a while, I realized this is the sizing grip (I had is set to SizingGrip=false, GripStyle=Hidden). Yet even with it hidden, it still hogs the space. I can't get any content on the status strip to extend all the way to the right.
How would you work around this? Note I can't just set the backcolor of the StatusStrip because the Status Label changes colors and has some fading effects.
The StatusStrip.Padding property is borked, it returns the wrong value for Padding.Right if the sizing grip is disabled. You can fix it in your form constructor, like this:
public Form1() {
InitializeComponent();
statusStrip1.Padding = new Padding(statusStrip1.Padding.Left,
statusStrip1.Padding.Top, statusStrip1.Padding.Left, statusStrip1.Padding.Bottom);
}
Using the Left property to specify Right is the fix. Don't bother submitting this bug to Connect, they won't fix it.
Have a look at this blog entry on MSDN. The question was about changing the size of the sizing grip manually, and I think using the ToolStrip Renderer as suggested could work for you also.
The problem I have so far, is that it removes the background color on a status label in the StatusStrip, so it's not a solution yet, but it's a start.
public MyForm()
{
InitializeComponent();
statusStrip1.Renderer = new MyRenderer();
}
private class MyRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderStatusStripSizingGrip(ToolStripRenderEventArgs e)
{
// don't draw at all
}
}
I had following problem: when I set tsslSeparator.Spring = true, my right label disappeared immediately after tsslSeparator lost focus. The issue appeared when sizing grip was enabled. When it was disabled, everything worked just fine.
The solution was to set right margin for right label to something different than 0.
tsslLogging.Margin = new Padding(0, 3, 2, 2); // this is necessary for right alignment of status bar label
Hope this helps somebody.
If Microsoft isn't interesting in fixing it, it seems like a proper fix should handle all orientations, and ideally fix all Status Strips (see my answer to Get All Children for definition of GetAllChildren)
public static StatusStrip FixPadding(this StatusStrip ss) {
if (!ss.SizingGrip) {
var fixpad = ss.Padding;
if (ss.Orientation == Orientation.Horizontal) {
if (ss.RightToLeft == RightToLeft.No)
fixpad.Right = fixpad.Left;
else
fixpad.Left = fixpad.Right;
}
else
fixpad.Bottom = fixpad.Top;
ss.Padding = fixpad;
}
return ss;
}
public static void FixStatusStripPadding(this Form f) {
foreach (var ss in f.GetAllChildren().OfType<StatusStrip>())
ss.FixPadding();
}
I have a Form and a DataGridView. I populate the DataGridView at runtime, so I want to know how do I resize the Form dynamically according to the size of the DataGridView? Is there any sort of property or method? Or do I have to determine the size myself and update accordingly?
You can find the actual width by count Columns width.
Don't forget that your form may be more complex and your should count other controls.
public class YourForm : Form
{
public YourForm()
{
DataGridView _dgv = new DataGridView() { Dock = DockStyle.Fill};
Controls.Add(_dgv);
}
public void CorrectWindowSize()
{
int width = WinObjFunctions.CountGridWidth(_dgv);
ClientSize = new Size(width, ClientSize.Height);
}
DataGridView _dgv;
}
public static class WinObjFunctions
{
public static int CountGridWidth(DataGridView dgv)
{
int width = 0;
foreach (DataGridViewColumn column in dgv.Columns)
if (column.Visible == true)
width += column.Width;
return width += 20;
}
}
int dgv_width = dataGridView1.Columns.GetColumnsWidth(DataGridViewElementStates.Visible);
int dgv_height = dataGridView1.Rows.GetRowsHeight(DataGridViewElementStates.Visible);
this.Width = dgv_width;
this.Height = dgv_height;
this.Width resizes this Form width.
Of course you've to add fixed values (for example margin, Form title heigth, ecc.).
With tests i've reached the values working for me (don't ask why...):
this.Width = dgv_width + 147;
this.Height = dgv_height + 47;
Normally controls adapt their sizes to the size of the containing form. To adjust the size of your form to the size of your DataGridView, you do have to determine the size yourself and then set the form's size to match, remembering to take into account the extra size required by the form's menu strip and/or toolbars, status bars or other controls.
In your case, it would probably be best not to resize the form to match the grid view control. Most likely, you will have many more rows in your grid view than could fit on your Windows screen, and you don't want to have a form that extends below the viewable desktop area. Generally speaking, this type of situation is exactly why you want to have a scrollable grid view - for viewing more data than can fit on the screen at one time.
I would go the other direction and size the grid to the form. (some users may have low res)
Set 'WindowState' property of the form => maximized. (optional)
Set 'anchor' property of the DGV => 'Top, Bottom, Left, Right'.
You may be able to make use of the PreferredSize property (MSDN PreferredSize entry). For DataGridView controls, I found that the preferred width and height were about 20 units bigger than I expected. I guess that the control might be calculating its preferred size taking scroll bars into account.
Another caveat I discovered is that the PreferredSize calculation will not be accurate immediately after adding or changing items in the table. To get around this I made a handler for the RowHeadersWidthChanged event.
Here is what worked for me:
class GridToy {
private DataGridView grid;
public GridToy(DataGridView dgv) {
grid = dgv;
grid.RowHeadersWidthChanged += AdjustWidth; // Event handler.
Layout();
}
public void Layout() {
// Just do some arbitrary manipulation of the grid.
grid.TopLeftHeaderCell.Value = "Some Arbitrary Title";
}
public void AdjustWidth() {
Control horizontal = grid.Controls[0]; // Horizontal scroll bar.
Control vertical = grid.Controls[1]; // Vertical scroll bar.
grid.Width = grid.PreferredSize.Width - vertical.Width + 1;
grid.Height = grid.PreferredSize.Height - horizontal.Height + 1;
}
}
You could set the Property " Height " to Auto in the form after classifying or using an ID and this should do it ,,
I just tried it .. and It worked
#form1{
background-color:white;
height:auto;
width:1500px;
border-top:medium solid #3399FF;
margin-top:100px;
margin-left:30px;
display: inline-block;
text-align: center;
float: none;
}
I'm just putting exactly what I did in case you got lost .. Don't worry about the other properties there for my design.
Set AutoSizeColumnsMode :Fill in Grid Properties