hvis du har den slags behov - er det næsten det nemmeste for dig at definere en baseform :
public class UCContainerForm : Page { public virtual string GetSomeString() { throw new NotImplementedException("method in baseclass is not implemented"); } }
Så kan du "slå" dine egne forms over den ved :
public class SomeForm : UCContainerForm { // hvor du så laver en implementering public override string GetSomeString() { return "somestring"; } }
Når du så har behov for at kalde en metode på formen fra din usercontrol, kan du bare :
string test = ((UCContainerForm)this.Page).GetSomeString();
Det ville ikke være unormalt at lave metoden i basen abstrakt, og dermed klassen abstrakt, men det er VS ikke spor glad for desværre.
Du kan opnå det samme ved at definere et interface (sådan kan jeg normalt bedst lide det med den slags - i særdeleshed hvis basen ikke har noget fallback-funktionalitet at byde ind med).
du kan sikre din usercontrol ved at spørge på :
if(!this.Page is UCContainerForm) // throw exception ell.
Hvis du bruger modellen med et interface, definerer du bare et sådant ved :
public interface ISomeThing { string GetSomeString(); }
og sørger for at implementere det på de forms hvor du vil have mulighed for at "kalde tilbage" fra en usercontrol :
public class SomeForm : Page, ISomeThing { // her tvinger kompileren dig så til at implementere interfacet : public string GetSomeString() { return "whatever"; } }
og fra userkontrollen bliver det så :
((ISomeThing)this.Page).GetSomeString();
og du kan på tilsvarende vis spørge om :
if(!this.Page is ISomeThing) /// ...
Du kan selvfølgelig også lave en kombination hvor du definerer interfacet, og implementerer det på en base, som du så specialiserer fra....
Men.... der er også en mulighed for at du løser opgaven mere eventbaseret, hvis du har den mulighed eller det giver mening.
thrytter: det fungerer jo desværre ikke, men ellers var det vist lige præcis den løsning jeg ledte efter!
snepnet: Jeg forstår desværre ikke ret meget af det du skriver, men det virker nu også utrolig omstændigt at skulle lave base-classes og begynde nedarvning, bare for at kunne kalde en metode.
Det kan da ikke passe at jeg ikke kan få fat i en reference til den aspx-side som mit usercontrol(ascx) befinder sig på????
Kan man måske gøre det via ascx's contructor : noget med at man sender "this" med ind til ascx fra aspx-siden???
hvis du bare skal have en reference til den side du befinder dig på, kan det gøres med this.Page, og du kan uden problemer trisse igennem sidens kontroltræ - f.eks.
Page.Controls[1] vil typisk være dit form-element (men du kan ikke væer sikker), og ovenstående kode vil derfor smide teksten "hej der" ind på formen.
this.Page er dog ikke en reference du kan bruge til noget særligt, hvis formålet er at du vil kalde en bestemt metode du selv har oprettet. Du kan sagtens smide this med over i en konstruktør, men det vil ikke give dig yderlige da du allerede kan nå det eksisterende Page-objekt som nævnt.
Hvis du ønsker at kalde specifikke metoder, bliver du nødt til at kende typen, eller forsøge dig via reflection (som du selv smed noget kode til tidligere).
At kende typen, ville så indebære at du i din usercontrol skrev noget i stil med : ((SomeSpecialPage)this.Page).SomeSpecialMethod(); Altså typecast af page-objekt til den bestemte type, men hvis du skriver kode som det, kan du jo ikke bruge din usercontrol på andre sider end den helt specifikke - og så kan det sådan set være ligemeget med at lave en kontrol.
Der er som jeg skrev flere forskellige måder du kan forbedre muligheder for at genbruge din kontrol - men det kræver altså at der er nogle typer der bliver nødt til at kende hinanden. (jeg synes bestemt ikke det er mindre omstændigt at benytte reflection for at kommunikere mellem egne forms og kontroller, end at definere en baseklasse).
Som jeg også skrev er der en mulighed for at du løser problemet mere eventbaseret... Altså at din kontrol kan affyre events, som du så kan abbonere på på siden - og så gøre det der nu giver mening på den aktuelle side, ved det aktuelle event. (på fuldstændig samme måde som du håndterer et click-event fra en knap).
Jeg vil gerne komme med eksempler, hvis du er interesseret, og jeg vil også meget gerne prøve at omformulere det jeg har skrevet, hvis du ikke kan få det til at give mening.
Og så tror jeg for øvrigt (når jeg tænker nærmere over det) ikke at dette vil fungere fra en kontrol : this.Page.Controls[1].Controls.Add(new LiteralControl("hej der"));
Du vil givetvis for en fejlmeddelelse hvis du prøver at modificere din kontainers kontroltræ, men det er - som du måske kan udlede af det jeg har skrevet - også hvad man kan begragte som et skidt design.
Kan du ikke skrive hvad du helt præcist har brug for... Så skal jeg komme med et bud.
jeg har løst problemet indtil videre ved at have en propertie i mit usercontrol som jeg sætter ovre fra aspx-siden som: usercontrol.propertie = this.Page;
Som du korrekt skriver bliver jeg nødt til at lave et typecast til den specifikke page-type. Det er der desværre ikke noget at gøre ved lige pt. - men jeg tænkte på om man ikke kunne lave noget dynamisk halløj?? At når jeg nu har referencen til siden - kan man så ikke finde typen på siden/refencen???
f.eks. reference = this.page; reference."Get_Class_Navn"() - for at kunne lave typecastet dynamisk skal jeg jo egentlig kun bruge class-navnet på siden( altså i dette tilfælde 'reference')
du behøver som nævnt ikke eksplicit at angive this.Page... Du kan fra enhver kontrol (altså typer med base eller bases base i System.Web.UI.Control) komme til page-objektet med this.Page.
this.Page er derfor fuldt ud gyldig fra den kode du har i din usercontrol.
der er masser af muligheder for at få oplyst typen, men hvis du skal bruge den til at kalde metoder, skal du stadig på et tidspunkt lave en .MetodeNavn(); som du stadig kun kan gøre hvis du har den specifikke type i koden. (altså... at bruge reflektion er jo stadig en mulighed).
Men... kan du ikke skrive hvad du helt præcist vil gøre... Så skal jeg sende et eksempel tilbage til dig. (altså... hvad er det du har brug for at kalde fra kontrollen - på den side kontrollen sidder på... Det er meget sansynligt at der er en nem og enkelt shortcut til det).
bsp_andreas>> Hvis mit eksempel ikke fungerer for dig, skyldes det måske at vi ikke bruger samme udviklingsværktøj - bruger selv Visual Studie VB.NET, og arbejder rent i code-behind eller hvad det nu kaldes.
namespace BSPsys.Tilbud { public class OpretTilbud : System.Web.UI.Page { protected BSPsys.Controls.tilbud_fiksTamp_userControl Tilbud_fiksTamp_userControl1; private int tilbudsnr;
Dette er således jeg løser problemet nu. Ved at have en propertie i mit usercontrol som kan indeholde en page-reference, kan jeg tilgå en metode på aspx-siden. Altså: int antal_for_ordre = ((BSPsys.Tilbud.OpretTilbud)SiteReference).GetAntal_for_Ordre();
Det er netop metoden GetAntal_for_ordre(), som befinder sig på aspx-siden, som jeg gerne vil kalde. Og kaldet skal komme inde fra ascx-filen.
Du må sige til hvis du skal bruge mere info. Håber det er forståeligt.
thrytter >> jeg bruger selv VS.NET, men koder dog i C#. Netop derfor har jeg prøvet at oversætte det du skrev til noget i c#, men kan åbenbart ikke få det til at køre.
Det skal ikke gøre nogen forskel hvilket udviklingsværktøj man bruger - det eneste som kan forandre noget er koden. Og at du skriver code-behind, betyder kun at du vælger at placere din kode i en aspx.vb-fil (i stedet for at skrive det direkte i din aspx-fil - under script-tags) Jeg bruger også code-behind.
med hensyn til din kode... du behøver ikke at angive referencen selv - du kan nøjes med : namespace BSPsys.Controls { public class tilbud_fiksTamp_userControl : System.Web.UI.UserControl { private void Calculate() { int antal_for_ordre = ((BSPsys.Tilbud.OpretTilbud)this.Page).GetAntal_for_Ordre(); } } }
men hvad der er lidt mere væsentligt... så har du ikke vist hvad det er der gør at metoden skal kaldes... opstår problemet fordi du ønsker at få kørt koden når der f.eks. trykkes på en knap der er placeret i din usercontrol ?
der er nogle andre ting omkring det, men inden jeg plaprer videre, må du gerne lige svare på ovenstående, og eventuelt skrive et par ord om formålet med din usercontrol (altså hvad den skal bruges til).
Troede heller ikke at der var den store forskel på .Parent i VB og C#, men det er der tilsyneladende. Mit VB eksempel virker med både .Parent og .Page, men kun sidstnævnte virker i C#.
Hvis det er tilfældet, må man sige at det er en temmelig grundlæggende forskel ?!? jeg arbejder normalt ikke i VB - så jeg skal ikke spille klog på det, men det ville være voldsomt hvis dine eksempler er helt identiske..... Jeg tror lige jeg prøver det selv.
Hmmm... Jeg kan ikke genskabe differensen her. Hvordan har du gjort ?
Jeg for nøjagtig samme output med disse to :
// VB Public Class SomeControl Inherits System.Web.UI.UserControl
#Region " Web Form Designer Generated Code "
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
End Sub
Private designerPlaceholderDeclaration As System.Object
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init InitializeComponent() End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Response.Write(Me.Parent.GetType().ToString()) Response.Write("<br>") Response.Write(Me.Page.GetType().ToString()) End Sub
End Class
// C# namespace EXP2 { using System; using System.Data; using System.Drawing; using System.Web; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls;
public class SomeControl1 : System.Web.UI.UserControl {
namespace CTest { using System; using System.Data; using System.Drawing; using System.Web; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls;
public class ucTest : System.Web.UI.UserControl { private void Page_Load(object sender, System.EventArgs e) { Response.Write(this.Parent.GetType().ToString()); Response.Write("<br>"); Response.Write(this.Page.GetType().ToString()); }
VB eksemplet var testet i et projekt, hvor UserControllen var indsat på en .aspx side som nedarver fra en base-class, der sørger for den grundlæggende funktionalitet og rendering af HtmlForm'en.
Da de enkelte sider i dette projekt ikke indeholder en HtmlForm, vil Me.Parent.GetType() og Me.Page.GetType() give samme resultat!
Det du skriver med at jeg ikke behøver at angive referencen selv: betyder det, at jeg ikke behøver at oprette "SiteReference"???
Kaldet som skal aktivere Calculate-metoden i ascx-filen kan komme både inde fra usercontrollet, men kan også komme som fra aspx-siden. Fra aspxsiden vil det være at brugeren trykker på en knap. Fra ascx kan det både være at brugeren trykker på en knap, men også hvis brugeren indtaster noget (altså event-driven).
Der er op mod 10-15 usercontrols placeret på aspx-siden - og det er vigtigt at hver af dem kan kalde en/flere metoder på aspx-siden. Næsten hvert usercontrol har en Calculate-metode. Det er meget vigtigt at hvert usercontrol's calculate() kan kaldes når brugeren trykker på en knap på aspx-siden. Men kan også være vigtigt hvis et andet usercontrol updates, at de andre så også odpateres.
Hvert usercontrol indeholder f.eks. et datagrid, hvori data kan indtastes, og når brugeren har indtastet/eller ændret data som står der i forvejen, skal en sum/felt(ikke i db) opdateres - enten ved at brugeren trykker på en knap ("opdater") eller ved et "onchangeEvent" på input-feltet. Den laver simpelthen en slags excel-beregning af en masse felter, som den udregner en sum for.
Måske lidt indviklet, men meningen er der måske. eller....?
Jeg har lavet et lille eksempel... du kan bare oprette en form der hedder bsp_andreas.aspx og så paste hele baduljen ind så du kan prøve det. (de eneste du skal skifte er det namespace der står øverst... til det der står i din code-behind når du opretter formen). Altså namespace EXP2 skal skiftes ud med det der står i den code-behind du for oprettet).
Hvis du synes der er meget der ser uvant ud for dig... så prøv at ignorere det til at starte med - og så bare check ud hvordan siden virker.
Fidusen er - at du fra en knap på formen kan få eksekverer alle dine calculate-metoder i dine egne kontroller, og hvis i en kontrol eksekverer calculate, kan det afstedkomme at calculate bliver kaldt i alle andre kontroller (det var sådan jeg forstod det du skrev).
Jeg sætter 10 ens kontroller ind - men glem det for nu.... det kunne lige så godt være 10 forskellige (jeg startede bare lige med en enkelt).
Jeg håber du kan se lidt af fidusen, og ellers spørg spørg spørg.
using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls;
// argument til brug i forbindelse med beregningsevent public class CalculationEventArgs : System.EventArgs { // bare privat variabel til resultatet private int result;
// property til resultatet public int Result { get{return result;} }
// kun en konstruktør der tager et resultat må anvendes public CalculationEventArgs(int result) { this.result = result; } }
// interface for "beregnere" public interface ICalculator { event CalculateEventHandler Calculation; int Result{get;} }
// bare en side public class bsp_andreas : System.Web.UI.Page { protected HtmlForm Form1; protected Button btnCalculateAll, btnClear; protected TextBox txtResult;
private int sumOfCalculations = 0;
private void Page_Load(object sender, System.EventArgs e) { // vi sætter en stak beregnere ind for(int i=0;i<10;i++) { Calculator calc = new Calculator(); calc.Calculation += new CalculateEventHandler(calc_Calculation); Form1.Controls.Add(calc); }
// så vi kan se resultatet txtResult = new TextBox(); txtResult.TextMode = TextBoxMode.MultiLine; txtResult.ReadOnly = true; txtResult.BackColor = Color.LightBlue; txtResult.Width = 232; txtResult.Height = 400; Form1.Controls.Add(txtResult);
// knap til udførelse af beregning btnCalculateAll = new Button(); btnCalculateAll.Text = "Calculate All"; btnCalculateAll.Width = 116; btnCalculateAll.Click += new EventHandler(btnCalculateAll_Click);
// knap til at slette indholdet af resutatboksen btnClear = new Button(); btnClear.Text = "Clear"; btnClear.Width = 116; btnClear.Click += new EventHandler(btnClear_Click);
// ind med sagerne Form1.Controls.Add(new LiteralControl("<br>")); Form1.Controls.Add(btnCalculateAll); Form1.Controls.Add(btnClear); }
// håndterer når der er udført en beregning i en kontrol private void calc_Calculation(object sender, CalculationEventArgs e) { Refresh(); }
// håndter at der trykkes på "beregn-det-hele-knappen" private void btnCalculateAll_Click(object sender, EventArgs e) { Refresh(); }
// opdaterer resultatet private void Refresh() { // starter med at nulstille resultatet sumOfCalculations = 0;
// her høster vi så værdien fra alle beregnere der er proppet direkte på formen foreach(Control c in this.Form1.Controls) { if(c is ICalculator) { sumOfCalculations += ((ICalculator)c).Result; txtResult.Text += "\n" + c.ToString(); } }
// event der kan abboneres på udefra public event CalculateEventHandler Calculation;
// property så resultatet kan hentes "udefra" - der beregnes hvis det er nødvendigt public int Result { get { EnsureChildControls(); if(_isDirty) DoCalculation(); return _result; } }
protected override void CreateChildControls() { // den første tekstboks txtVal1 = new TextBox(); txtVal1.Text = "1"; txtVal1.Width = 50; txtVal1.TextChanged += new EventHandler(txtVal_TextChanged);
// den anden tekstboks txtVal2 = new TextBox(); txtVal2.Text = "1"; txtVal2.Width = 50; txtVal2.TextChanged += new EventHandler(txtVal_TextChanged);
// tekstboks til resultatet txtResult = new TextBox(); txtResult.ReadOnly = true; txtResult.Width = 50; txtResult.BackColor = Color.Silver;
// knap så beregningen kan foretages fra kontrollen btnCalculate = new Button(); btnCalculate.Text = "Calculate"; btnCalculate.Click += new EventHandler(btnCalculate_Click);
// og de indsættes this.Controls.Add(txtVal1); this.Controls.Add(txtVal2); this.Controls.Add(txtResult); this.Controls.Add(btnCalculate);
// og basen kaldes (std) base.CreateChildControls (); }
// bare en convenience-metode til at affyre eventet private void FireCalculation(CalculationEventArgs e) { if(Calculation != null) Calculation(this, e); }
// når der klikkes på knappen - ønskes beregningen udført, // og hvis der skulle være nogle der lytter - får de at vide at beregningen er udført private void btnCalculate_Click(object sender, EventArgs e) { DoCalculation(); FireCalculation(new CalculationEventArgs(this.Result)); }
// sørger bare for at beregne værdien private void DoCalculation() { _result = int.Parse(txtVal1.Text) * int.Parse(txtVal2.Text); _isDirty = false; this.txtResult.Text = _result.ToString(); }
// angiver at der skal genberegnes fordi teksten er skiftet private void txtVal_TextChanged(object sender, EventArgs e) { _isDirty = true; }
// overskrivninga af tostring() så den returnerer regnestykket public override string ToString() { return String.Format("{0}*{1}={2}", txtVal1.Text, txtVal2.Text, Result); } } }
hej igen. jeg fik desværre ikke tid til at se på det i går, men sidder og kigger lidt på det nu, lige inden morgenmaden :)
Det ser ud til at være noget jeg sagtens kan bruge - da det er super smart at man kan aktivere alle control's på samme tid.
Det må jo være en form for pattern du bruger til at opbygge det der. Hvad hedder det?? Listener... eller noget???
Jeg arbejder videre med det.
Kan det også bruges til at; hente en variabel (eller kalde en metode som returnerer en variabel) fra aspx-siden?? Det er fordi at nogle af controllerne skal bruge en variabel, som befinder sig på aspx-siden - til at udføre beregningen.
alletiders :o) jeg vil gerne vente med at sende et eksempel på det sidste - indtil du har fået den første udgave "op under neglene". det er helt bevidst at det er udeladt indtil videre.
men hvis du har ovenstående op at køre på din æske - skal jeg gerne udvide lidt i aften :o)
Hej - jeg har lidt problemer med at få det til at køre. Det brokker sig og siger at jeg ikke har implementeret interfacet - men det er mig og maskinen nu ikke enige om...
Jeg har lige et par spm.: 1) hvor skal jeg skrive delegate't?? 2) hvor skal jeg skrive interfacet??
Jeg kunne godt tænke mig at, især interfacet, lå i en fil for sig. Jeg er ikke så glad for at det hele står i en lang fil.
pt. ser mit system nogenlunde således ud: BSPsys.Controls.tlb_repro_userControl.ascx = som er det control, der skal implementere ICalculator BSPsys.Tilbud.OpretTilbud.aspx.cs = som er selve siden
Begge skal jo have adgang til interfacet, så spørgsmålet er om jeg ikke skal oprette en mappe i roden, til interfacet: BSPsys.Interfaces - og placere det her??
det skal du bare gøre helt som du synes bedst.... den eneste grund til at jeg havde lagt det hele i den samme var at det så skulle være nemmere at paste, og efterfølgende få til at virke :o) når ud i VS skriver ", <interfacenavn> efter en klasse - plejer man at kunne trykke på tabulatoren, hvorefter stubs for det der ligger under interfacet bliver skrevet ind i klassen.
Når du implementerer et interface - er det det samme som at stille krav om at der er noget bestemt der skal implementeres.
halløj - nu er den der NÆSTEN!!! Juuhuu, tror jeg.
Men jeg har ET problem:
foreach(Control c in this.Form1.Controls) { if(c is ICalculator) { sumOfCalculations += ((ICalculator)c).Result; Response.Write(sumOfCalculations + "\n"); txtResult.Text += "\n" + c.ToString(); } }
jeg indsætter ikke mine controls programmatisk med: Form1.Controls.Add(calc); De bliver bare indsat på aspx-siden. Derfor kan jeg ikke finde "this.Form1"
hvad gør jeg??? Jeg har prøvet med .page og alt muligt, men den finder ikke min controller i metoden. Altså den kommer aldrig ind i "if(c is ICalculator)"
det var godt at den faldt i god jord :o) jeg kan ikke komme til at lave det før iaften - men hvis du stadig gerne vil have det udvidet med en mulighed for at kalde tilbage på siden - siger du bare til. mvh
jamen jeg er helt sikkert interesseret i at kunne kalde den anden vej også. Det ville være rigtig cool, da jeg som beskrevet, skal bruge en variabel som findes på siden og flere af controllerne skal have adgang til den.
Jeg er self. også villig til at hæve pointene, så du i det mindste får lidt ud af dit store arbejde.
Så er der lidt frisk kode... Jeg har bare udvidet det lidt - og poster hele eksemplet her igen :´
fidusen i koden er, at såfremt ICalculatoren sidder på en side der implementerer ICalculatorContainer, vil der blive sat en lille meddelelse om hvor stor en del af den samlede sum, resultatet fra den ICalculator man har klikket i udgør. Resultatet beregnes selvfølgelig udfra den samlede sum, som hentes fra den ICalculatorContainer den sidder på.
Det er denne kode her det drejer sig om :
if(this.Page is ICalculaterContainer) { double partOfSum = ((double)this.Result / (double)(((ICalculaterContainer)this.Page).Total)) * 100; lblPartOfSum.Text = String.Format("Udgør {0}% af det hele", partOfSum.ToString("c")); } (plus selvfølgelig det, at siden implementerer ICalculatorContainer).
hvis siden ikke implementerer ICalculatorContainer - sker der ikke noget ved det... man må bare undvære oplysningen.
jeg håber du kan få det til at hænge sammen.
mvh
using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls;
// argument til brug i forbindelse med beregningsevent public class CalculationEventArgs : System.EventArgs { // bare privat variabel til resultatet private int result;
// property til resultatet public int Result { get{return result;} }
// kun en konstruktør der tager et resultat må anvendes public CalculationEventArgs(int result) { this.result = result; } }
// interface for "beregnere" public interface ICalculator { event CalculateEventHandler Calculation; int Result{get;} }
// og et nyt interface til en beregningscontainer public interface ICalculaterContainer { int Total{get;} }
// bare en side public class bsp_andreas : System.Web.UI.Page, ICalculaterContainer { protected HtmlForm Form1; protected Button btnCalculateAll, btnClear; protected TextBox txtResult;
private int sumOfCalculations = 0;
// her er så den property der er defineret under interfacet, // og som en calculator kunne finde på at spørge på. public int Total { get{return sumOfCalculations;} }
private void Page_Load(object sender, System.EventArgs e) { // vi sætter en stak beregnere ind for(int i=0;i<10;i++) { Calculator calc = new Calculator(); calc.Calculation += new CalculateEventHandler(calc_Calculation); Form1.Controls.Add(calc); }
// så vi kan se resultatet txtResult = new TextBox(); txtResult.TextMode = TextBoxMode.MultiLine; txtResult.ReadOnly = true; txtResult.BackColor = Color.LightBlue; txtResult.Width = 232; txtResult.Height = 400; Form1.Controls.Add(txtResult);
// knap til udførelse af beregning btnCalculateAll = new Button(); btnCalculateAll.Text = "Calculate All"; btnCalculateAll.Width = 116; btnCalculateAll.Click += new EventHandler(btnCalculateAll_Click);
// knap til at slette indholdet af resutatboksen btnClear = new Button(); btnClear.Text = "Clear"; btnClear.Width = 116; btnClear.Click += new EventHandler(btnClear_Click);
// ind med sagerne Form1.Controls.Add(new LiteralControl("<br>")); Form1.Controls.Add(btnCalculateAll); Form1.Controls.Add(btnClear); }
// håndterer når der er udført en beregning i en kontrol private void calc_Calculation(object sender, CalculationEventArgs e) { Refresh(); }
// håndter at der trykkes på "beregn-det-hele-knappen" private void btnCalculateAll_Click(object sender, EventArgs e) { Refresh(); }
// opdaterer resultatet private void Refresh() { // starter med at nulstille resultatet sumOfCalculations = 0;
// her høster vi så værdien fra alle beregnere der er proppet direkte på formen foreach(Control c in this.Form1.Controls) { if(c is ICalculator) { sumOfCalculations += ((ICalculator)c).Result; txtResult.Text += "\n" + c.ToString(); } }
// label til angivelse af hvor stor en del denne værdi udgører af summen af Calculators på formen protected Label lblPartOfSum;
// event der kan abboneres på udefra public event CalculateEventHandler Calculation;
// property så resultatet kan hentes "udefra" - der beregnes hvis det er nødvendigt public int Result { get { EnsureChildControls(); if(_isDirty) DoCalculation(); return _result; } }
protected override void CreateChildControls() { // den første tekstboks txtVal1 = new TextBox(); txtVal1.Text = "1"; txtVal1.Width = 50; txtVal1.TextChanged += new EventHandler(txtVal_TextChanged);
// den anden tekstboks txtVal2 = new TextBox(); txtVal2.Text = "1"; txtVal2.Width = 50; txtVal2.TextChanged += new EventHandler(txtVal_TextChanged);
// tekstboks til resultatet txtResult = new TextBox(); txtResult.ReadOnly = true; txtResult.Width = 50; txtResult.BackColor = Color.Silver;
// knap så beregningen kan foretages fra kontrollen btnCalculate = new Button(); btnCalculate.Text = "Calculate"; btnCalculate.Click += new EventHandler(btnCalculate_Click);
// label lblPartOfSum = new Label();
// og de indsættes this.Controls.Add(txtVal1); this.Controls.Add(txtVal2); this.Controls.Add(txtResult); this.Controls.Add(btnCalculate); this.Controls.Add(lblPartOfSum);
// og basen kaldes (std) base.CreateChildControls (); }
// bare en convenience-metode til at affyre eventet private void FireCalculation(CalculationEventArgs e) { if(Calculation != null) Calculation(this, e); }
// når der klikkes på knappen - ønskes beregningen udført, // og hvis der skulle være nogle der lytter - får de at vide at beregningen er udført private void btnCalculate_Click(object sender, EventArgs e) { DoCalculation(); FireCalculation(new CalculationEventArgs(this.Result)); if(this.Page is ICalculaterContainer) { double partOfSum = ((double)this.Result / (double)(((ICalculaterContainer)this.Page).Total)) * 100; lblPartOfSum.Text = String.Format("Udgør {0}% af det hele", partOfSum.ToString("c")); } }
// sørger bare for at beregne værdien private void DoCalculation() { _result = int.Parse(txtVal1.Text) * int.Parse(txtVal2.Text); _isDirty = false; this.txtResult.Text = _result.ToString(); }
// angiver at der skal genberegnes fordi teksten er skiftet private void txtVal_TextChanged(object sender, EventArgs e) { _isDirty = true; }
// overskrivninga af tostring() så den returnerer regnestykket public override string ToString() { return String.Format("{0}*{1}={2}", txtVal1.Text, txtVal2.Text, Result); } } }
hej andreas :o) jeg smider et svar her hvis du kunne bruge det til noget. mvh
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.