#c# #winforms
Вопрос:
У меня есть приложение Windows Forms. Я создал пользовательский UserControl
интерфейс, который расширяется Panel
. Внутри одной из моих форм есть кнопка, которая должна открывать эту панель при нажатии.
Однако после щелчка я все еще не вижу панель, отображаемую в форме.
Код формы
public partial class IngredientMenu : Form
{
public IngredientMenu()
{
InitializeComponent();
}
private void btnOpenRegisterBasePanel_Click(object sender, EventArgs e)
{
BaseIngredientPanel baseIngredientPanel = new BaseIngredientPanel();
baseIngredientPanel.Location = new Point(257, 63);
baseIngredientPanel.Show();
baseIngredientPanel.BringToFront();
Console.WriteLine("panel should open");
Console.WriteLine(baseIngredientPanel.Visible);
Console.WriteLine(baseIngredientPanel.Location);
}
}
Код панели
public partial class BaseIngredientPanel : UserControl
{
public BaseIngredientPanel()
{
InitializeComponent();
}
private void btnRegisterBaseIngredient_Click(object sender, EventArgs e)
{
IngredientContext ingredientContext = new IngredientContext();
if (ingredientContext.RegisterIngredient(txtName, txtUnit, lblBaseIngredientNameValidation, lblBaseIngredientUnitValidation))
{
MessageBox.Show("Ingredient Registered."
, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtName.Text = "";
txtUnit.Text = "";
}
else
{
MessageBox.Show("There are errors in the form fields."
, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void BaseIngredientPanel_Load(object sender, EventArgs e)
{
Console.WriteLine("I AM OPEN");
}
}
Кроме того, сообщение «Я ОТКРЫТ» никогда не появляется даже после щелчка, поэтому кажется, что в целом он даже не загружает элемент управления.
Как я могу открыть панель после нажатия кнопки? Я бы предпочел не перетаскивать панель вручную в конструктор, так как мне нужно иметь около 5 панелей, а дизайнер просто попытается упаковать их, как русскую куклу.
Комментарии:
1. Вам нужно добавить ее в родительскую коллекцию элементов управления. Или установите его родительское свойство. Показывать не нужно, так как значение visible по умолчанию равно true.
2. Теперь, если вы хотите скрыть это, вы можете сделать это, а затем снова показать по мере необходимости..
Ответ №1:
У всех элементов управления пользовательского интерфейса должен быть родитель, которому они принадлежат с помощью метода Controls.Add() . Родительским элементом может быть форма или другие элементы управления (не все будут принимать дочерние элементы). например, ваша панель может быть родительской для текстовых полей, выпадающих списков, меток и т. Д.
private void btnOpenRegisterBasePanel_Click(object sender, EventArgs e)
{
BaseIngredientPanel baseIngredientPanel = new BaseIngredientPanel();
baseIngredientPanel.Location = new Point(257, 63);
//Add user panel to form.
this.Controls.Add(baseIngredientPanel);
//You will probably not need these two rows any more. Try it out! But make sure your usercontrol has Visible = true.
baseIngredientPanel.Show();
baseIngredientPanel.BringToFront();
}
Редактировать:
чтобы ответить на ваши вопросы в комментарии ниже
Если вам нужно внести много изменений в пользовательский интерфейс одновременно, то также лучше использовать this.SuspendLayout()
и this.ResumeLayout()
временно приостановить логику пользовательского интерфейса. Это поможет повысить производительность в таких случаях. См. https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.suspendlayout?view=windowsdesktop-5.0 для получения более подробной информации
Если вам нужно будет удалить элементы управления на каком-то этапе после их добавления, у вас есть два варианта.
- Создайте отдельную
List<BaseIngredientPanel>
(также) для хранения ваших элементов управления при добавлении их в форму. Это использует этот список, чтобы найти и удалить их с помощьюthis.Controls.Remove()
метода - При его создании укажите свое
BaseIngredientPanel
уникальное имя и используйте его для поиска и удаления элемента управления с помощьюthis.Controls.Remove()
метода. У всех элементов управления уже есть свойство Name, поэтому вы можете использовать это.
Комментарии:
1. Должен ли я беспокоиться о добавлении элемента управления в коллекцию слишком много раз? Я предполагаю, что она добавляется с каждым щелчком мыши, разве это не замедлит работу пользовательского интерфейса? есть ли безопасный способ удалить элемент управления, когда мне нужно его закрыть и открыть другой?
Ответ №2:
Если вы хотите отобразить форму, класс должен быть производным от Form . BaseIngredientPanel
Это не форма, это пользовательский элемент управления.
Пользовательские элементы управления похожи на другие элементы управления, такие как кнопки, выпадающие списки, меню, DataGridViews и т. Д. Обычно вы используете Visual Studio Designer для отображения их в форме. В редких случаях вы делаете это программно.
Я создал пользовательский пользовательский элемент управления, который расширяет панель.
Чего вы действительно хотите:
- Я хочу создать панель особого типа, которая ведет себя как стандартная панель, с небольшими отличиями. Пользователи моего класса могут использовать почти все свойства моей специальной панели: производные от панели классов
- Я хочу создать панель особого типа, которая ведет себя как стандартная панель. Я хочу контролировать, какие методы могут вызывать пользователи моей специальной панели: создайте класс, производный от UserControl, и поместите на него панель.
- Я хочу создать форму, на которую я хочу поместить панель. Эта панель имеет некоторое поведение, которое я использую только в этой форме.
Если вы хотите создать панель особого типа, которая будет использоваться повторно в нескольких формах, используйте деривацию. Производная от Panel или UserControl зависит от того, насколько надежным вы хотите, чтобы ваш класс был, и сколько методов панели могут вызывать пользователи вашего класса.
Если ваша специальная панель будет использоваться только в одной форме, не беспокойтесь о создании специального класса Panel. Создайте форму, содержащую панель.
Используйте стандартную панель в специальной форме
Если вы решили, что вам не нужно повторно использовать поведение этой панели, вы можете просто поместить ее в новую форму. Используйте Visual Studio Designer для создания формы и размещения на ней панели. Подпишитесь на события панели, на которые вы хотите реагировать.
Если вы хотите, чтобы в форме также была кнопка, также используйте Visual Studio designer, чтобы добавить кнопку и подписаться на событие Button_Clicked.
Чтобы отобразить форму панели, вы должны решить, является ли форма панели модельной или немодальной.
- Модальный: оператор может использовать эту форму только до тех пор, пока она не будет закрыта. Он не может использовать другие формы этого приложения. Это, безусловно, наиболее используемый вид формы: при выборе меню или нажатии кнопки: показать форму панели, использовать форму панели, закрыть форму панели, после чего родительская форма может прочитать результаты формы панели и действовать соответствующим образом. Модальные диалоговые окна отображаются с помощью Form.ShowDialog .
- Немодальный: пока отображается форма панели, оператор может переключиться обратно на родительскую форму и взаимодействовать с ней. Это используется не очень часто. Вы можете использовать ее, чтобы отобразить дополнительную информацию о состоянии родительского окна или приложения, например, положение мыши или выбранную фигуру, которую вы будете рисовать. С помощью Form.Show() отображается немодальное диалоговое окно. Имейте в виду, что перед закрытием родительской формы вам придется закрыть немодальное диалоговое окно
Показать модальный
Хорошим примером является форма OpenFileDialog
В вашей родительской форме:
using (var form = new OpenFileDialog())
{
// set properties of the OpenFileDialog before showing
form.InitialDirectory = this.GetInitialDirectory();
form.DefaultExt = ".txt";
...
// Show the Form as a modal box and wait until it is Closed
DialogResult dialogResult = form.ShowDialog(this);
// the operator has closed the form. Interpret the result:
if (dialogResult == DialogResult.OK)
{
string fileName = form.FileName();
this.OpenFile(fileName);
}
}
Немодальный: оператор может вернуться к этой форме
private MyPanel PanelForm {get; set;} = null;
private void ShowMyPanel()
{
if (this.PanelForm != null) return; // panel already shown
this.PanelForm = new MyPanel();
// set properties:
this.PanelForm.DisplayedItems = ...
// show the PanelForm
this.PanelForm.Show();
}
Оператор может вернуться к этой форме и, вероятно, закрыть эту форму. В этом случае вам придется закрыть форму панели:
private void CloseMyPanel()
{
if (this.MyPanel != null)
{
this.MyPanel.Close();
this.MyPanel.Dispose();
this.MyPanel = null;
}
}
private void OnFormClosing(object sender, ...)
{
// if MyPanel is shown, is it allowed to Close this form AND myPanel
// or should you warn the operator to close MyPanel first?
if (this.MyPanel != null)
{
this.CloseMyPanel(); // close immediately
// or:
MessageBox.Show(..., "Please close Panelbox first");
}
}
Конечно, вы также должны отреагировать, если оператор закроет панель. Перед отображением окна панели:
this.MyPane.Closed = OnMyPanelClosed;
private void OnMyPanelClosed(object sender, ...)
{
if (object.ReferenceEquals(sender, this.MyPanel)
{
// my panel is closed
this.MyPanel = null;
Вы не можете удалить панель, потому что она все еще используется. Панель показывает Dispose при закрытии.
Специальный класс панели
Если у вас есть специальный класс Panel (производный от Panel или UserControl), то после компиляции элемент управления panel отображается в панели инструментов Visual Studio designer.
Вы должны использовать использовать Visual Studio designer для создания формы и поместить панель в форму:
class MyPanelForm : Form
{
public MyPanelForm()
{
InitializeComponent();
Если вы использовали Visual Studio designer для добавления специальной панели, то вы найдете ее в InitializeComponent
. Вы также можете добавить ее самостоятельно в конструкторе. В этом случае не забудьте добавить ее в this.components
, чтобы ваша панель была удалена при удалении MyPanelForm.
Чтобы отобразить MyPanelForm, используйте либо ShowDialog
или Show
, как описано в предыдущем разделе.