Aktualizace vlastností WinForm controlů z UserControls   otázka

C#, Reflexe

Zdravím,

mám problém jak získat přístup k ovládacím prvkům v hlavním formuláři (frmMain) z dynamicky načetlého UserControlu (ucTest). Chtěl bych měnit vlastnosti (např. TextBox.Text, Label.Text apod.) na hlavním formuláři z UserControlu.

Zkoušel jsem "experimentovat" s reflexí, childControl.Parent i vyhledáváním Controlů, ale vše bezúspěšně :-( Jediné co jede (ale je to prasárna kterou nechci použít) je vytvořit pro UserControl novou vlastnost (property) a tam si předávat úplnou instanci hlavního formuláře (frmMain) .

Pro úplnost přikládám jak to nyní funguje, chyba je znázorněna v bodu 4:

1)

Mám vytvořenou třídu pro UserControly:

    /// <summary>
    /// Base user control public class 
    ///  - for extend properties standard user controls
    /// </summary>
    public class BaseUserControl : UserControl
    {
        /// <summary>
        /// User control name
        /// </summary>
        private string myUserControlName = String.Empty;
        [Category("BaseUserControl"),
        Description("User control name"),
        Browsable(true)]
        public string UserControlName
        {
            get { return myUserControlName; }
            set { myUserControlName = value; }
        }
    }

2)

Ve formuláři (frmMain) volám dle stisku v menu metodu:

this.LoadUserControl(new UserControls.FileSystem.ucTest());

3)

Tato metoda (LoadUserControl) obsahuje:

        /// <summary>
        /// Load user control to panelMain
        /// </summary>
        /// <param name="myControl"></param>
        private void LoadUserControl(BaseUserControl myControl)
        {
            // declare variables
            string strUserControlImagePath = String.Empty;

            try
            {
                // remove the last loaded user control
                if (splitcontainerMain.Panel2.Controls.Count > 0)
                    splitcontainerMain.Panel2.Controls.RemoveAt(0);

                // load current control and docked them
                splitcontainerMain.Panel2.Controls.Add(myControl);
                myControl.Dock = DockStyle.Fill;

                // append informations and image
                lblUserControlHeading.Text = myControl.UserControlName;
                //TODO: lblUserControlDescription.Text = myControl.UserControlDescription;
                //TODO: pictureboxUserControl.Image = myControl.UserControlImage;
            }
            catch (Exception myException)
            {
                // write event to log file
                EventManager.WriteToEventLog(myException.ToString(), EventLogType.Error);
            }
        }

4) Pokud dojde k načtení UserControlu, je začátek kódu UserControlu:

public partial class ucTest : BaseUserControl
{
        /// <summary>
        /// UserControl load method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ucTest_Load(object sender, EventArgs e)
        {
	    // TOTO FUNGUJE KOREKTNĚ
            // append user control properties
            this.UserControlName = "NÁZEV - TEST";
        }

        private void btnExecute_Click(object sender, EventArgs e)
        {
	    // TADY NEDOKÁŽU ZMĚNIT VLASTNOST this.UserControlName (ev. controlu lblHeading.Text ve frmMain)

	    // ver36
            //if (this.Parent != null && this.Parent.GetType() != typeof(frmMain))
            //{
            //    Label aaa = (this.Parent as frmMain).Controls["lblUserControlHeading"] as Label;
            //    aaa.Text = "šáž íezýáíewzfgisudhgfghdsghuízfáísdfýdsf žf dsýáížfdýsá";
            //}
	}
.....
}

Děkuji, Petr

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Podle mě by bylo asi nejlepší, kdybyste si na tom Vašem prvku udělal událost:V prvku


public class MojeVlastnostChangedEventArgs
{
  public string StaráHodnota { get; private set; }
  public string NováHodnota { get; private set; }
  internal MojeVlastnostChangedEventArgs(string staráHodnota, string nováHodnota)
  {
    StaráHodnota = staráHodnota;
    NováHodnota = nováHodnota;
  }
}
public delegate void MojeVlastnostChangedEventHandler(object sender, MojeVlastnostChangedEventArgs e);
public event MojeVlastnostChangedEventHandler MojeVlastnostChanged;

A pak když budete měnit tu vlastnost, tak v jejím setteru a nebo v nějaké privátní metodě voláné jejím setterem tu událost vyvoláte:

private string _MojeVlastnost;
public string MojeVlastnost
{
  get { return _MojeVlastnost; }
  set 
  {
    OnMojeVlastnostChanged(_MojeVlastnost, value);
    _MojeVlastnost = value;
  }
}
private void OnMojeVlastnostChanged(string staráHodnota, string nováHodnota)
{
  var handler = MojeVlastnostChanged;
  // Toto je tam pro kontrolu, zda je na událost něco navěšené
  if(hnadler != null) 
  { 
    var args = new MojeVlastnostChangedEventArgs(staráHodnota, nováHodnota);
    handler(this, args);
  }
}

Ve formuláři

var můjUserControl = new MůjUserControl();
// sender bude Váš prvek, ale musí se přetypovat z objektu
// e bude MojeVlastnostChangedEventArgs jak předepisuje delegát
můjUserControl.MojeVlastnostChanged += (sender, e) => { MessageBox.Show(string.Format("Vlastnost změněna z '{0}' na '{1}' v prvku {2}.", e.StaráHodnota, e.NováHodnota, sender)); };

Pár slov k eventám naleznete na MSDN. Je tam i příklad:

http://msdn.microsoft.com/en-us/library/...

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Zdravím,

v první řadě děkuji za hezký příklad a jakým směrem se mám ubírat.

Podařilo se mi rozchodit změnu vlastností a přikládám řešení.

1)

Přidat do private void LoadUserControl(BaseUserControl myControl) zpracování MojeVlastnostChanged;

 /// <summary>
        /// Load user control to panelMain
        /// </summary>
        /// <param name="myControl"></param>
        private void LoadUserControl(BaseUserControl myControl)
        {
            // declare variables
            string strUserControlImagePath = String.Empty;

            try
            {
                // sender bude Váš prvek, ale musí se přetypovat z objektu
                // e bude MojeVlastnostChangedEventArgs jak předepisuje delegát
                myControl.MojeVlastnostChanged += (sender, e) =>
                {
                    MessageBox.Show(string.Format("Vlastnost změněna z '{0}' na '{1}' v prvku {2}.",
                        e.StaráHodnota, e.NováHodnota, sender));

                    lblUserControlHeading.Text = e.NováHodnota;
                };
                
                // remove the last loaded user control
                if (splitcontainerMain.Panel2.Controls.Count > 0)
                    splitcontainerMain.Panel2.Controls.RemoveAt(0);

                ...

2)

Pro otestování změna textu v UserControlu

private void btnExecute_Click(object sender, EventArgs e)
        {
            this.MojeVlastnost = "xxx ss dddddd";
            this.MojeVlastnost = "222222";
            ...

Prosím ještě o radu (nedokážu si odvodit co je lepší řešení), kdy používat události. Pokud mám na formuláři frmMain např. 3 labely a z toho jen u 1-noho chci měnit text za běhu, je lepší vytvořit 3 události a nebo 2 vlastnosti (property) a 1 událost na změnu textu?

Děkuji, Petr

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Rozhodně bych Vám doporučil udělat dedikovanou událost každé vlastnosti, která hraje nějakou roli při překreslování UI a práci s daty. Ve Windows Forms je to dobrá praxe, frameworkové prvky také mají spoustu vlastností souvisejících s jejich vykreslováním, uspořádáním atd.

Druhou možností je implementace INotifyPropertyChanged rozhraní, pak byste ošetřil jen vlastnost PropertyChanged a v ní byste mohl na základě jména změněné vlastnosti vyšetřit, kde došlo ke změnám. Ovšem tato technika se používá hlavně u Data Bindingu a není běžná pro formulářové prvky.

http://msdn.microsoft.com/en-us/library/...

Obecně bych řekl, že pokud si nevíte rady podobně jako u tohoto, zda použít jednu nebo více událostí, inspirujte se u .NET frameworku samotného. Ovládací prvky jak ve Windows Forms, tak ve WPF mají spousty a spousty událostí pro většinu svých vlastností.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Souhlasím s vytvořením události, předávat instanci formuláře je blbost, protože jeho ovládací prvky jsou stejně Private.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback