Home > Blockchain >  Fill WinForms Control to Parent
Fill WinForms Control to Parent

Time:01-09

I am attempting to build a simple text editor in F# with WinForms. I would like to know how to get items to fill their parent containers most easily, and I am finding that a text box is not filling its parent despite its Dock property being set to DockStyle.Fill. I would like both the top MenuStrip and the RichTextBox to fill the parent containers and take up the whole form (as you'd expect to see in a text editor). Here is a screenshot demonstrating the issue:

Text Edit area too small!

As you can see, it would be nice to have both the MenuStrip and RichTextBox to fill the entire form.

Here is the code (along with the .fsproj file):

Program.fs:

module FsEdit.Program

open System
open System.Windows.Forms

[<EntryPoint; STAThread>]
let main argv =
    Application.Run FsEdit.MainForm.MainForm
    0

MainForm.fs:

[<RequireQualifiedAccess>]
module FsEdit.MainForm

open System.Windows.Forms

// MenuBar
let private FileMenuTab =
    new ToolStripMenuItem(
        Text = "File"
    )

let private EditMenuTab =
    new ToolStripMenuItem(
        Text = "Edit"
    )

let private AboutMenuTab =
    new ToolStripMenuItem(
        Text = "About"
    )

let private MainMenuStrip =
    new MenuStrip(
        Text = "MainMenuStrip"
    )

let private allMenuStripItems =
    [|
        FileMenuTab
        EditMenuTab
        AboutMenuTab
    |]
    |> Array.map (fun tab -> tab :> ToolStripItem)
    
MainMenuStrip.Items.AddRange(allMenuStripItems)

// Text Editor
let private MainTextBox =
    let richTextBox = new RichTextBox(
        Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a eleifend nunc. Suspendisse non purus varius, ullamcorper arcu et, vehicula lacus. Integer pellentesque facilisis interdum. Aliquam id leo arcu. Nam mauris nisl, semper eget massa sed, aliquam convallis lacus. Etiam a neque blandit, sollicitudin nisl quis, ornare dui. Aliquam nec lorem sit amet arcu iaculis elementum rutrum eu velit. Curabitur dignissim blandit ligula at efficitur. Curabitur id justo quis tortor egestas ultrices. Nam arcu quam, ullamcorper id velit quis, aliquam finibus libero. Pellentesque semper fermentum sem a scelerisque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;"
    )
    richTextBox.Dock <- DockStyle.Fill
    richTextBox.Anchor <- AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Top
    richTextBox.AllowDrop <- true
    richTextBox.AutoSize <- true
    richTextBox

let private MainTextBoxPanel =
    let p = new FlowLayoutPanel()
    p.Dock <- DockStyle.Fill
    p.WrapContents <- false
    p.FlowDirection <- FlowDirection.TopDown
    p.Anchor <- AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Top
    p

MainTextBoxPanel.Controls.Add(MainMenuStrip)
MainTextBoxPanel.Controls.Add(MainTextBox)

// MainForm
let MainForm =
    let form = new Form(
        Text = "FsEdit"
    )
    form.Width <- 800
    form.Height <- 600
    form
    
MainForm.Controls.Add(MainTextBoxPanel)

FsEdit.fsproj:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net7.0-windows</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
        <UseWpf>true</UseWpf>
    </PropertyGroup>

    <ItemGroup>
        <Compile Include="MainForm.fs" />
        <Compile Include="Program.fs" />
    </ItemGroup>

</Project>

How do I get these Control objects to fill their respective parents successfully?

CodePudding user response:

The behavior is expected for a FlowLayoutPanel having TopDown flow direction. According to the enter image description here

CodePudding user response:

I tried both the regular Panel approach per @Reza Aghaei and the TableLayoutPanel approach per @Jimi and decided to go with the latter as I was still getting overlap with the plain Panel objects. I also added a StatusStrip to the bottom of the Form, but found that if I added it to the TableLayoutPanel it would not display correctly even with the Dock set to DocStyle.Bottom (enter image description here

MainWindow.fs:

[<RequireQualifiedAccess>]
module FsEdit.MainForm

open System.Windows.Forms
open System.Drawing

// Main panel
let private MainTableLayoutPanel =
    let t = new TableLayoutPanel()
    t.Dock <- DockStyle.Fill
    t
    
// Main menu strip
let private FileMenuTab =
    new ToolStripMenuItem(
        Text = "File"
    )

let private EditMenuTab =
    new ToolStripMenuItem(
        Text = "Edit"
    )

let private AboutMenuTab =
    new ToolStripMenuItem(
        Text = "About"
    )

let private MainMenuStrip =
    let m = new MenuStrip(
        Text = "MainMenuStrip"
    )
    m

let private allMenuStripItems =
    [|
        FileMenuTab
        EditMenuTab
        AboutMenuTab
    |]
    |> Array.map (fun tab -> tab :> ToolStripItem)
    
MainMenuStrip.Items.AddRange(allMenuStripItems)

// Text Editor
let private MainTextBox =
    let richTextBox = new RichTextBox(
        Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut a eleifend nunc. Suspendisse non purus varius, ullamcorper arcu et, vehicula lacus. Integer pellentesque facilisis interdum. Aliquam id leo arcu. Nam mauris nisl, semper eget massa sed, aliquam convallis lacus. Etiam a neque blandit, sollicitudin nisl quis, ornare dui. Aliquam nec lorem sit amet arcu iaculis elementum rutrum eu velit. Curabitur dignissim blandit ligula at efficitur. Curabitur id justo quis tortor egestas ultrices. Nam arcu quam, ullamcorper id velit quis, aliquam finibus libero. Pellentesque semper fermentum sem a scelerisque. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;"
    )
    richTextBox.Dock <- DockStyle.Fill
    // richTextBox.Anchor <- AnchorStyles.Left ||| AnchorStyles.Right ||| AnchorStyles.Top ||| AnchorStyles.Bottom
    richTextBox.AllowDrop <- true
    richTextBox.AutoSize <- true
    richTextBox

let private MainStatusBar =
    let s = new StatusStrip()
    s.Dock <- DockStyle.Bottom // if anything other than "bottom" does not show up
    s

// Add controls to main panel
MainTableLayoutPanel.Controls.Add(MainMenuStrip)
MainTableLayoutPanel.Controls.Add(MainTextBox)

// MainForm
let MainForm =
    let form = new Form(
        Text = "FsEdit"
    )
    form.Width <- 800
    form.Height <- 600
    form.MinimumSize <- Size(320, 240)
    form
    
MainForm.Controls.Add(MainTableLayoutPanel)
MainForm.Controls.Add(MainStatusBar) // Adding to MainTableLayoutPanel makes it size incorrectly even with DockStyle.Bottom

CodePudding user response:

An option to make life easier for one who wants WinForms UI with F# is creating the UI with a Windows Forms Designer and using design UI with drag and drop and all the design-time features, then adding the reference the WinForms project to the F# project and add F# code. Follow the steps to see how it works in action:

enter image description here

Example - WinForms UI Designer F# Code

  1. Create UI Project: Create a WinForms Class Library (.NET 6) and set its name to WinFormsFS.UI

    You can create a WinForms Project or a WinForms Control Library as well and modify the project and files. The only thing that matters here, is the project output type which we'd like it to be class library, and we don't need main entry point in this project.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Library</OutputType>
        <TargetFramework>net6.0-windows</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
        <ImplicitUsings>enable</ImplicitUsings>
      </PropertyGroup>
    </Project>
    

    If you created a WinForms project, remove the Program.cs, or Form1. For WinForms Class Library, remove Class1, and for WinForms Control Library remove UserControl1. We don't need them for this examample.

  2. Add Form: Add a new Form, and set its name MainFormUI

  3. Add controls: Drop a MenuStrip, StatusStrip and a RichTextBox, and let them use their default names. The MenuStrip will be docked to top automatically, and the StatuStrip will be docked to bottom. You can setup all properties, or add menu items to the menu strip.

  4. Configure properties: Dock the RichTextBox to Fill (using property editor, and setting Dock property, or using the smart tags panel

  • Related