将WinForms控件填充到父级

bksxznpy  于 2023-01-09  发布在  其他
关注(0)|答案(3)|浏览(222)

我尝试用WinForms在F#中建立一个简单的文本编辑器。我想知道如何让项目最容易地填充它们的父容器,我发现尽管文本框的Dock属性设置为DockStyle.Fill,但该文本框没有填充其父容器。我希望顶部的MenuStripRichTextBox都填充父容器并占据整个表单(正如您期望在文本编辑器中看到的那样)。以下是演示该问题的屏幕截图:

如您所见,如果同时使用MenuStrip和RichTextBox来填充整个表单,那就太好了。
下面是代码(沿着.fsproj文件):
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>

如何让这些Control对象成功地填充它们各自的父对象?

8qgya5xd

8qgya5xd1#

此行为是具有TopDown流向的FlowLayoutPanel的预期行为。根据documentation
这是在FlowLayoutPanel控件中锚定和对接的一般规则:对于垂直流向,FlowLayoutPanel控件从列中最宽的子控件计算隐含列的宽度。此列中具有锚或Dock属性的所有其他控件都将对齐或拉伸以适应此隐含列。
如果要将控件停靠到顶部并填充,则不需要FlowLayoutPanel。请改用Panel。
您可以使用以下布局之一:

- Form
    - Menu (Dock = Top)
    - RichTextBox (Dock = Fill)

或者,如果出于某种原因,您希望将菜单和文本编辑器都作为container托管在同一面板中:

- Form
    - Panel (Dock = Fill)
        - Menu (Dock = Top)
        - RichTextBox (Dock = Fill)

***重要说明:***请注意向窗体中添加控件的顺序。控件的Z顺序很重要,会影响结果。控件按相反的Z顺序停靠。您可能需要了解有关Windows窗体中的how to dock and anchor controls的详细信息。
要了解更多信息:

对窗体使用以下代码,它会将Menu停靠到顶部,将RichTextBox停靠到Fill,将StatusStrip停靠到底部,而不使用任何其他容器:

[<RequireQualifiedAccess>]
module FsEdit.MainForm

open System.Windows.Forms
open System.Drawing

// 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.AllowDrop <- true
    richTextBox.AutoSize <- true
    richTextBox

let private MainStatusBar =
    let s = new StatusStrip()
    s.Dock <- DockStyle.Bottom 
    s

// MainForm
let MainForm =
    let form = new Form(
        Text = "FsEdit"
    )
    form.Width <- 800
    form.Height <- 600
    form.MinimumSize <- Size(320, 240)
    form
    
MainForm.Controls.Add(MainTextBox)
MainForm.Controls.Add(MainMenuStrip)
MainForm.Controls.Add(MainStatusBar)

vxf3dgd4

vxf3dgd42#

对于需要使用F#的WinForms UI的用户来说,一个使其工作更轻松的方法是使用Windows窗体设计器创建UI,并使用具有拖放功能和所有设计时功能的设计UI,然后将WinForms项目的引用添加到F#项目并添加F#代码。请按照以下步骤查看它的实际工作方式:

示例- WinForms用户界面设计器+ F#代码

1.**创建UI项目:**创建WinForms类库(.NET 6)并将其名称设置为WinFormsFS.UI
你可以创建一个WinForms项目或者WinForms控件库,也可以修改项目和文件。这里唯一重要的是我们希望它是类库的项目输出类型,并且我们不需要这个项目中的主入口点。

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

如果创建的是WinForms项目,请删除Program.cs或Form 1。对于WinForms类库,请删除Class 1;对于WinForms控件库,请删除UserControl 1。在本示例中不需要它们。
1.**增加表单:**增加一个新表单,并设置其名称MainFormUI
1.**添加控件:**拖放MenuStrip、StatusStrip和RichTextBox,并使用它们的默认名称。MenuStrip将自动停靠在顶部,StatuStrip将停靠在底部。您可以设置所有属性,也可以向菜单条添加菜单项。
1.**配置属性:**将RichTextBox停靠到Fill(使用属性编辑器并设置Dock属性,或使用智能标记面板🞂并选择“在父容器中停靠”)。
1.**更改访问修饰符:**对于要在F#代码中使用的控件,需要将访问修饰符更改为public。为此,请选择RichTextBox,然后在属性浏览器中将其修饰符设置为Public。
1.**创建F#项目:**创建一个名为WinFormsFS. Code的F#控制台应用程序。并将设置为启动项目。将输出类型更改为win exe并使用winfows窗体。项目文件应如下所示:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>
</Project>

1.**添加WinForms项目引用:**右键单击F#项目并添加对WinForms项目的引用。
1.**为UI添加代码:**使用以下代码添加文件MainForm.fs

namespace WinFormsFS.Code
open System.Windows.Forms
open WinFormsFS.UI

type MainForm() as this = 
    inherit MainFormUI()
    do
        this.richTextBox1.Text <- "Lorem ipsum!"

1.**添加启动代码:**将Program.fs修改为以下内容:

module WinFormsFS.Code.Program

open System
open System.Windows.Forms

[<EntryPoint; STAThread>]
let main args =
    Application.EnableVisualStyles()
    Application.SetCompatibleTextRenderingDefault(false)
    Application.SetHighDpiMode(HighDpiMode.SystemAware) |>ignore   
    Application.Run (new WinFormsFS.Code.MainForm())
    0

按f5键运行程序并查看输出。(确保启动项目是F#项目)

30byixjq

30byixjq3#

我对@Reza Aghaei尝试了常规的Panel方法,对@Jimi尝试了TableLayoutPanel方法,并决定使用后者,因为我仍然与普通的Panel对象重叠。但是我发现如果我将它添加到TableLayoutPanel中,即使将Dock设置为DocStyle.Bottom,它也不会正确显示(see here).(如果我在F#中找到更好的WinForms开发编程解决方案,我当然会更新。)
下面是一个屏幕截图,后面是更新后的代码:

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

相关问题