Cel mai bun mod de a accesa un control pe un alt formular în Windows Forms?

În primul rând, aceasta este o întrebare despre o aplicație desktop care utilizează Windows Forms, nu o ASP.NET o> întrebare.

Trebuie să interacționez cu controalele pe alte forme. Încerc să accesez comenzile folosind, de exemplu, următoarele ...

otherForm.Controls["nameOfControl"].Visible = false;

Nu funcționează așa cum m-aș aștepta. Încheiem cu o excepție aruncată de la Main . Cu toate acestea, dacă fac controalele public în loc de private , le pot accesa direct, așa că ...

otherForm.nameOfControl.Visible = false;

Dar este cel mai bun mod de a face acest lucru? Face ca comenzile public pe cealaltă formă să fie considerate "cele mai bune practici"? Există o modalitate "mai bună" de a accesa controalele pe un alt formular?

Explicație suplimentară:

Acesta este de fapt un fel de urmărire la o altă întrebare pe care am întrebat-o, Cea mai bună metodă pentru crearea unui dialog de preferințe pentru vizualizarea unui arbore? tipul de interfață în C #? . Răspunsul pe care l-am primit a fost mare și a rezolvat multe, multe probleme organizatorice pe care le aveam în ceea ce privește menținerea UI drept și ușor de a lucra atât în ​​timpul run-time cât și în timpul design-ului. Cu toate acestea, aceasta a adus la iveală această chestiune de neglijare a controlului cu ușurință a altor aspecte ale interfeței.

Practic, am o formă de rădăcină care instanțiază o mulțime de alte forme care stau într-un panou pe forma rădăcină. De exemplu, un buton radio de pe una dintre aceste sub-formulare ar putea avea nevoie să modifice starea unei pictograme de banda de stare pe forma principală, rădăcină. În acest caz, am nevoie de subformul pentru a vorbi cu controlul din banda de stare a formularului parent (root). (Sper că are sens, nu într-un fel "cine este pe primul").

0
fr hi bn
Accesați aceste controale extern dintr-un fir separat?
adăugat autor Tanerax, sursa
Asigurați-vă că ați pus acest lucru în clasa proprie care ia o formă în constructor. Trebuie să implementeze interfața IDisposable și să fie proprietatea dispusă când este terminată. De asemenea, trebuie să folosească urmărirea de referință (creșterea/micșorarea unui număr întreg, astfel încât acesta să nu provoace probleme) și să ascundă comenzile doar atunci când aceasta merge de la 0 la 1. Și numai să le arătăm din nou când merge de la 1 la 0.
adăugat autor TamusJRoyce, sursa

14 răspunsuri

În loc să faceți controlul public, puteți crea o proprietate care să îi controleze vizibilitatea:

public bool ControlIsVisible
{
     get { return control.Visible; }
     set { control.Visible = value; }
}

Acest lucru creează un accesoriu corespunzător acelui control care nu va expune întregul set de proprietăți al controlului.

0
adăugat

Eu personal aș recomanda NU să o facă ... Dacă răspunde la un fel de acțiune și trebuie să-și schimbe aspectul, aș prefera să ridic un eveniment și să-l las să se ordoneze ...

Acest tip de cuplare între forme întotdeauna mă face nervos. Încerc mereu să păstrez interfața UI ca fiind ușoară și independentă cu putință.

Sper ca asta ajuta. Poate că ați putea extinde scenariul dacă nu?

0
adăugat
uneori cuplarea este bine ... programatorul ar trebui să poată decide. Acesta este motivul pentru care accesul protejat este prostie.
adăugat autor eat_a_lemon, sursa

@ Lars, apel bun la trecerea în jurul referințelor formularului, l-am văzut și eu pe mine. Neplăcut. Niciodată nu le-a văzut că le-a trecut în jos pe stratul BLL deși! Asta nici nu are sens! Asta ar fi putut afecta serios performanța? Dacă undeva în BLL a fost păstrată referința, forma ar rămâne în memorie corectă?

Ai simpatia mea! ;)


@Ed, RE comentariul dvs. despre realizarea Formularelor UserControls. Dylan a subliniat deja că formula rădăcină instanțează formulare mici pentru copii, dând impresia unei aplicații MDI (unde presupun că utilizatorii ar dori să închidă diverse Formulare). Dacă sunt corect în această ipoteză, cred că ar fi cel mai bine păstrate ca forme. Desigur, deschis la corecție, deși :)

0
adăugat

Primul nu funcționează desigur. Comenzile de pe un formular sunt private, vizibile doar pentru acel form prin design.

A face totul public nu este, de asemenea, cel mai bun mod.

Dacă aș vrea să expun ceva în lumea exterioară (ceea ce poate însemna și o altă formă), fac o proprietate publică pentru ea.

public Boolean nameOfControlVisible
{
    get { return this.nameOfControl.Visible; }
    set { this.nameOfControl.Visible = value; }
}

Puteți utiliza această proprietate publică pentru a ascunde sau a afișa controlul sau pentru a solicita proprietatea de vizibilitate curentă de control:

otherForm.nameOfControlVisible = true;

De asemenea, puteți expune controale complete, dar cred că este prea mult, ar trebui să faceți vizibile numai proprietățile pe care doriți să le utilizați cu adevărat din afara formularului curent.

public ControlType nameOfControlP
{
    get { return this.nameOfControl; }
    set { this.nameOfControl = value; }
}
0
adăugat

După ce ați citit detaliile suplimentare, sunt de acord cu robcthegeek : ridicați un eveniment. Creați un EventArgs personalizat și treceți prin el parametrii necesari.

0
adăugat

M-aș ocupa de asta în forma părintească. Puteți notifica celălalt formular că trebuie să se modifice printr-un eveniment.

0
adăugat

Formele copilului dumneavoastră trebuie să fie Forme? Ar putea fi controale ale utilizatorilor? În acest fel, ele ar putea să genereze cu ușurință evenimente pentru ca forma principală să se ocupe și ar fi mai bine să încapsulezi logica lor într-o singură clasă (cel puțin, logic, ele sunt deja după toate clasele).

@Lars: Ești chiar aici. Acesta a fost ceva ce am făcut în primele mele zile și nu am fost nevoit să o fac de atunci, de aceea am sugerat pentru prima dată că am organizat un eveniment, dar cealaltă mea metodă ar sparge cu adevărat orice aparență de încapsulare.

@ Rob: Yup, sună despre dreapta :). 0/2 pe aceasta ...

0
adăugat

Ar trebui să accesați numai conținutul unei vizualizări de la alta dacă creați controale/module/componente mai complexe. În caz contrar, ar trebui să faceți acest lucru prin arhitectura standard-View-Controller: Ar trebui să conectați starea activată a comenzilor care vă interesează la un predicat la nivel de model care furnizează informațiile corecte.

De exemplu, dacă vroiam să activez un buton Salvare numai atunci când s-au introdus toate informațiile necesare, aș avea o metodă predicată care să spună când obiectele modelului care reprezintă acel formular sunt într-o stare care poate fi salvată. Apoi, în contextul în care aleg să activez butonul, aș folosi rezultatul acelei metode.

Acest lucru are ca rezultat o separare mult mai curată a logicii de afaceri de logica de prezentare, permițând ambelor dintre ele să evolueze mai independent? permițându-vă să creați un front-end cu multiple back-end-uri sau multiple front-end-uri cu un singur back-end cu ușurință.

De asemenea, va fi mult, mult mai ușor de scris pentru testele de unitate și de acceptare, deoarece poți să urmezi un " Trust But Verify ", făcând acest lucru:

  1. Puteți scrie un set de teste care să configureze obiectele modelului în diferite moduri și să verifice dacă predicatul "este sigur" returnează un rezultat adecvat.

  2. Puteți scrie un set separat care verifică dacă butonul Salvare este conectat într-o manieră adecvată la predicatul "este salvat" (indiferent de contextul dvs., în Cocoa pe Mac OS X acest lucru ar fi adesea printr-o legare).

Atâta timp cât ambele seturi de teste au loc, puteți avea încredere că interfața dvs. de utilizator va funcționa așa cum doriți.

0
adăugat

Sunt de acord cu utilizarea evenimentelor pentru acest lucru. Din moment ce bănuiesc că construiți o aplicație MDI (de când creați mai multe formulare copil) și creează dinamic dinamic și s-ar putea să nu știe când să vă dezabonați de la evenimente, aș recomanda să aruncați o privire la Modele de evenimente slabe . Din păcate, acest lucru este disponibil numai pentru cadrele 3.0 și 3.5, dar ceva similar poate fi implementat destul de ușor, cu referințe slabe.

Cu toate acestea, dacă doriți să găsiți un control într-o formă bazată pe referința formularului, nu este suficient să examinați pur și simplu colecția de control a formularului. Deoarece fiecare control are o colecție de control propriu, va trebui să recurgeți prin toate acestea pentru a găsi un control specific. Puteți face acest lucru cu aceste două metode (care pot fi îmbunătățite).

public static Control FindControl(Form form, string name)
{
    foreach (Control control in form.Controls)
    {
        Control result = FindControl(form, control, name);

        if (result != null)
            return result;
    }

    return null;
}

private static Control FindControl(Form form, Control control, string name)
{
    if (control.Name == name) {
        return control;
    }

    foreach (Control subControl in control.Controls)
    {
        Control result = FindControl(form, subControl, name);

        if (result != null)
            return result;
    }

    return null;
}
0
adăugat

Acesta arată ca un prim candidat pentru separarea prezentării de modelul de date. În acest caz, preferințele dvs. ar trebui să fie stocate într-o clasă separată care actualizează evenimentele ori de câte ori o anumită proprietate se modifică (căutați în INotifyPropertyChanged dacă proprietățile dvs. sunt un set discret sau într-un eveniment unic dacă acestea sunt chei bazate pe text mai libere ).

În vizualizarea arborescentă, veți face modificările în modelul preferințelor dvs., apoi va declanșa un eveniment. În celelalte forme, vă veți abona la modificările care vă interesează. În procesul de tratare a evenimentelor pe care îl utilizați pentru a vă abona la modificările proprietăților, utilizați acest lucru.InvocateRequired pentru a vedea dacă sunteți pe firul drept pentru a face interfața sunați, dacă nu, apoi utilizați această opțiune.BeginInvoke pentru a apela metoda dorită pentru a actualiza formularul.

0
adăugat

Poti

  1. Creați o metodă publică cu parametrul necesar pe formularul copil și formați-o din formularul părinte (cu distribuție validă)
  2. Creați o proprietate publică pe formularul copil și accesați-o din formularul părinte (cu distribuție validă)
  3. Creați un alt constructor pe formularul copil pentru a seta parametrii de inițializare ai formularului
  4. Creați evenimente personalizate și/sau utilizați clase (statice)

Cele mai bune practici ar fi # 4 dacă utilizați formulare non-modale.

0
adăugat

Cu proprietatea (evidențiată) pot obține instanța clasei MainForm. Dar aceasta este o practică bună? Ce ai recomanda?

Pentru aceasta, folosesc proprietatea MainFormInstance care rulează pe metoda OnLoad.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LightInfocon.Data.LightBaseProvider;
using System.Configuration;

namespace SINJRectifier
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            UserInterface userInterfaceObj = new UserInterface();
            this.chklbBasesList.Items.AddRange(userInterfaceObj.ExtentsList(this.chklbBasesList));
            MainFormInstance.MainFormInstanceSet = this; //Here I get the instance
        }

        private void btnBegin_Click(object sender, EventArgs e)
        {
            Maestro.ConductSymphony();
            ErrorHandling.SetExcecutionIsAllow();
        }
    }

    static class MainFormInstance  //Here I get the instance
    {
        private static MainForm mainFormInstance;

        public static MainForm MainFormInstanceSet { set { mainFormInstance = value; } }

        public static MainForm MainFormInstanceGet { get { return mainFormInstance; } }
    }
}
0
adăugat
  1. Utilizați un dispozitiv de gestionare a evenimentelor pentru a notifica altui formular cu care să se ocupe.
  2. Creați o proprietate publică pe formularul copil și accesați-o din formularul părinte (cu o distribuție validă).
  3. Creați un alt constructor pe formularul copil pentru a seta parametrii de inițializare ai formularului
  4. Creați evenimente personalizate și/sau utilizați clase (statice).

Cele mai bune practici ar fi # 4 dacă utilizați formulare non-modale.

0
adăugat

Pasul 1:

string regno, exm, brd, cleg, strm, mrks, inyear;

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    string url;
    regno = GridView1.Rows[e.NewEditIndex].Cells[1].Text;
    exm = GridView1.Rows[e.NewEditIndex].Cells[2].Text;
    brd = GridView1.Rows[e.NewEditIndex].Cells[3].Text;
    cleg = GridView1.Rows[e.NewEditIndex].Cells[4].Text;
    strm = GridView1.Rows[e.NewEditIndex].Cells[5].Text;
    mrks = GridView1.Rows[e.NewEditIndex].Cells[6].Text;
    inyear = GridView1.Rows[e.NewEditIndex].Cells[7].Text;

    url = "academicinfo.aspx?regno=" + regno + ", " + exm + ", " + brd + ", " +
          cleg + ", " + strm + ", " + mrks + ", " + inyear;
    Response.Redirect(url);
}

Pasul 2:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string prm_string = Convert.ToString(Request.QueryString["regno"]);

        if (prm_string != null)
        {
            string[] words = prm_string.Split(',');
            txt_regno.Text = words[0];
            txt_board.Text = words[2];
            txt_college.Text = words[3];
        }
    }
}
0
adăugat