Заполнить элемент управления WinForms родительским

Я пытаюсь создать простой текстовый редактор на F# с помощью WinForms. Я хотел бы знать, как проще всего заставить элементы заполнять свои родительские контейнеры, и я обнаружил, что текстовое поле не заполняет своего родителя, несмотря на то, что для его свойства Dock установлено значение DockStyle.Fill. Я бы хотел, чтобы верхние MenuStrip и RichTextBox заполнили родительские контейнеры и заняли всю форму (как вы ожидаете увидеть в текстовом редакторе). Вот скриншот, демонстрирующий проблему:

Как видите, было бы неплохо иметь и MenuStrip, и RichTextBox для заполнения всей формы.

Вот код (вместе с файлом .fsproj):

Программа.фс:

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>

Как мне заставить эти объекты управления успешно заполнять своих соответствующих родителей?

Используйте панель вместо FlowLayoutPanel.

Reza Aghaei 08.01.2023 05:30

@RezaAghaei не лучше: imgur.com/Hk3pnKl

LSM07 08.01.2023 05:34

Кроме того, не добавляйте MenuStrip и RichTextBox в одну и ту же панель. Вы можете закрепить MenuStrip в верхней части (в форме) и панель, содержащую RTB для заполнения. Обратите внимание, что вы не можете одновременно закрепить и привязать элементы управления. Выберите один или другой. Вы также можете использовать TableLayoutPanel (который позволяет дочерние элементы управления, а не FLP - напрямую) в качестве контейнера как для MenuStrip, так и для контейнера RichTextBox и пристыковать TLP к Fill

Jimi 08.01.2023 05:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
80
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Поведение ожидается для FlowLayoutPanel с направлением потока TopDown. Согласно документации:

Это общее правило для привязки и закрепления в элементе управления FlowLayoutPanel: для вертикального направления потока элемент управления FlowLayoutPanel вычисляет ширину подразумеваемого столбца на основе самого широкого дочернего элемента управления в столбце. Все остальные элементы управления в этом столбце со свойствами Anchor или Dock выравниваются или растягиваются, чтобы соответствовать этому подразумеваемому столбцу.

Если вы хотите закрепить элементы управления сверху и заполнить, вам не нужна FlowLayoutPanel. Вместо этого используйте панель.

Вы можете использовать любой из следующих макетов:

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

Или, если по какой-то причине вы хотите разместить и меню, и текстовый редактор на той же панели, что и контейнер:

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

Важное примечание. Обратите внимание на порядок добавления элементов управления в форму. Z-порядок элементов управления важен и влияет на результат. Элементы управления закрепляются в обратном порядке по оси Z. Возможно, вы захотите узнать больше о том, как закреплять и закреплять элементы управления в Windows Forms.

Узнать больше:

Пример 1. Закрепление меню сверху, RichTextBox для заполнения и StatusStrip снизу

Используйте следующий код для формы, он прикрепит Menu к верхней части, RichTextBox к заполнению и 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)

Порядок добавления элементов управления также важен и влияет на результат стыковки.

Reza Aghaei 08.01.2023 05:55

Я думаю, что все эти ответы хороши и обеспечивают хорошую отправную точку для базовой разработки графического интерфейса на F# с помощью WinForms. Я приму этот ответ и, надеюсь, в будущем это поможет другим людям начать разработку графического интерфейса на чистом F#, чего, как мне кажется, очень не хватает в мире разработки F#. Спасибо!

LSM07 09.01.2023 04:52

Я бы также добавил акцент на «порядок добавления элементов управления», и это то, с чем разработчикам нужно экспериментировать, когда они добавляют элементы управления в формы или другие элементы управления, поскольку поведение может быть немного неинтуитивным.

LSM07 09.01.2023 04:54

Спасибо за отзыв, добавил раздел в ответ, чтобы подчеркнуть важность z-порядка.

Reza Aghaei 09.01.2023 05:02

Этот пост прямо отвечает на ваш вопрос, и я согласен, имеет смысл пометить его как принятый. Я поделился другим ответом (не как прямое решение вашей проблемы), а как общее решение для проектов, которые разрабатывают многие формы и пользовательский интерфейс; в таких случаях использование дизайнера WinForms очень поможет, так как вы будете использовать дизайнер графического интерфейса и увидите, что вы получите.

Reza Aghaei 09.01.2023 05:04

Я попробовал как обычный подход Panel от @Reza Aghaei, так и подход TableLayoutPanel от @Jimi и решил использовать последний, поскольку я все еще перекрывался с простыми Panel объектами. Я также добавил StatusStrip внизу формы, но обнаружил, что если я добавлю его к TableLayoutPanel, он не будет отображаться правильно, даже если для Dock установлено значение DocStyle.Bottom (см. здесь). (Конечно, я обновлю, если найду лучшие программные решения на 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

TableLayoutPanel работает, но в этом сценарии совершенно не нужен.

Reza Aghaei 08.01.2023 23:21

Я обновил ответ примером кода, правильно состыковав его без использования дополнительного контейнера. Посмотрите на скриншот, чтобы увидеть результат. Также обратите внимание на порядок, в котором я добавил элементы управления. Z-порядок элементов управления важен и влияет на результат. Элементы управления закрепляются в обратном порядке по оси Z. Если вы хотите узнать больше, посмотрите ссылки в моем ответе, особенно это на.

Reza Aghaei 09.01.2023 00:51

Вариант упростить жизнь для тех, кто хочет использовать пользовательский интерфейс WinForms с F#, — это создать пользовательский интерфейс с помощью конструктора Windows Forms и использовать пользовательский интерфейс дизайна с перетаскиванием и всеми функциями времени разработки, а затем добавить ссылку на проект WinForms в проект F#. и добавьте код F#. Следуйте инструкциям, чтобы увидеть, как это работает в действии:

Пример — конструктор пользовательского интерфейса WinForms + код F#

  1. Создайте проект пользовательского интерфейса: создайте библиотеку классов 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 или Form1. Для библиотеки классов WinForms удалите Class1, а для библиотеки элементов управления WinForms удалите UserControl1. Нам они не нужны для этого примера.

  2. Добавить форму: добавьте новую форму и установите ее имя MainFormUI

  3. Добавьте элементы управления: удалите MenuStrip, StatusStrip и RichTextBox и позвольте им использовать их имена по умолчанию. MenuStrip будет автоматически закреплен сверху, а StatuStrip — снизу. Вы можете настроить все свойства или добавить пункты меню в полосу меню.

  4. Настройте свойства: прикрепите RichTextBox к Fill (с помощью редактора свойств и настройки свойства Dock или с помощью панели смарт-тегов 🞂 и выбора Dock in parent container).

  5. Изменить модификаторы доступа. Для элементов управления, которые вы хотите использовать в коде F#, вам необходимо изменить модификатор доступа на общедоступный. Для этого выберите RichTextBox и в обозревателе свойств установите для его модификаторов значение Public.

  6. Создайте проект F#: создайте консольное приложение F# с именем WinFormsFS.Code. И установить как стартовый проект. Измените тип вывода на 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>
    
  7. Добавить ссылку на проект WinForms: щелкните правой кнопкой мыши проект F# и добавьте ссылку на проект WinForms.

  8. Добавьте код для пользовательского интерфейса: добавьте файл MainForm.fs со следующим кодом:

    namespace WinFormsFS.Code
    open System.Windows.Forms
    open WinFormsFS.UI
    
    type MainForm() as this = 
        inherit MainFormUI()
        do
            this.richTextBox1.Text <- "Lorem ipsum!"
    
  9. Добавьте код для запуска: измените 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#)

Гораздо более простой подход для сложного пользовательского интерфейса (с использованием дизайнера).

Reza Aghaei 09.01.2023 03:01

Другие вопросы по теме