Tried something like this:
HttpApplication app = s as HttpApplication; //s is sender of the OnBeginRequest event
System.Web.UI.Page p = (System.Web.UI.Page)app.Context.Handler;
System.Web.UI.WebControls.Label lbl = new System.Web.UI.WebControls.Label();
lbl.Text = "TEST TEST TEST";
p.Controls.Add(lbl);
when running this I get "Object reference not set to an instance of an object." for the last line...
How do I get to insert two lines of text (asp.net/html) at specific loactions in the original file?
And how do I figure out the extension of the file (I only want to apply this on aspx files...?
Its simplier than you think:
public void Init(HttpApplication app)
{
app.PreRequestHandlerExecute += OnPreRequestHandlerExecute;
}
private void OnPreRequestHandlerExecute(object sender, EventArgs args)
{
HttpApplication app = sender as HttpApplication;
if (app != null)
{
Page page = app.Context.Handler as Page;
if (page != null)
{
page.PreRender += OnPreRender;
}
}
}
private void OnPreRender(object sender, EventArgs args)
{
Page page = sender as Page;
if (page != null)
{
page.Controls.Clear(); // Or do whatever u want with ur page...
}
}
If the PreRender Event isn't sufficient u can add whatever Event u need in the PreRequestHandlerExecute EventHandler...
I'm not sure, but I don't think you can use an HttpModule to alter the Page's control tree (please correct me if I'm wrong). You CAN modify the HTML markup however, you'll have to write a "response filter" for this. For an example, see http://aspnetresources.com/articles/HttpFilters.aspx, or google for "httpmodule response filter".
It seems like the HttpFilter solution is doing the trick here :o)
If I had used MOSS/.net 2.x+ I could have used Runes version or just added my tags in a master page...
Super suggestions and after my test of the solution, I'll accept miies.myopenid.com's solution as it seems to solve thar actual issue
There have been some changes in how you write HttpModules in IIS7 as compared to IIS6 or 5, so it might be that my suggestion is not valid if you are using IIS7.
If you use the Current static property of the HttpContext you can get a reference to the current context. The HttpContext class has properties for both the Request (HttpRequest type) and the Response (HttpResponse) and depending on where which event you are handling (Application.EndRequest maybe?) you can perform various actions on these objects.
If you want to change the content of the page being delivered you will probably want to do this as late as possible so responding to the EndRequest event is probably the best place to do this.
Checking which file type that was requested can be done by checking the Request.Url property, maybe together with the System.IO.Path class. Try something like this:
string requestPath = HttpContext.Current.Request.Url.AbsolutePath;
string extension = System.IO.Path.GetExtension(requestPath);
bool isAspx = extension.Equals(".aspx");
Modifying the content is harder. You may be able to do it in one of the events of the Context object, but I am not sure.
One possible approach could be to write your own cusom Page derived class that would check for a value in the Context.Items collection. If this value was found you could add a Label to a PlaceHolder object and set the text of the label to whatever you wanted.
Something like this should work:
Add the following code to a HttpModule derived class:
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(BeginRequest);
}
void BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
HttpRequest request = context.Request;
string requestPath = HttpContext.Current.Request.Url.AbsolutePath;
string extension = System.IO.Path.GetExtension(requestPath);
bool isAspx = extension.Equals(".aspx");
if (isAspx)
{
// Add whatever you need of custom logic for adding the content here
context.Items["custom"] = "anything here";
}
}
Then you add the following class to the App_Code folder:
public class CustomPage : System.Web.UI.Page
{
public CustomPage()
{ }
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (Context.Items["custom"] == null)
{
return;
}
PlaceHolder placeHolder = this.FindControl("pp") as PlaceHolder;
if (placeHolder == null)
{
return;
}
Label addedContent = new Label();
addedContent.Text = Context.Items["custom"].ToString();
placeHolder .Controls.Add(addedContent);
}
}
Then you you modify your pages like this:
public partial class _Default : CustomPage
Note that the inheritance is changed from System.Web.UI.Page to CustomPage.
And finally you add PlaceHolder objects to your aspx files wherever you want you custom content.
Related
I have to change inner html code before showing it in the WebBrowser.
Test page - http://aksmod.ru/skajrim-mod-kukri-ot-aksyonov-v5-0/
I tried to use AngleSharp.Scripting but it doesn't work correctly (the ads doesn't load)
var config = new Configuration().WithDefaultLoader().WithJavaScript();
var document = BrowsingContext.New(config).OpenAsync(address).Result;
//do something
return document.DocumentElement.OuterHtml;
later I thought about LoadCompleted, but the result was the same
private void Wb_LoadCompleted(object sender, NavigationEventArgs e)
{
Console.WriteLine("Loaded");
string url = e.Uri.ToString();
if (!(url.StartsWith("http://") || url.StartsWith("https://")))
{ }
if (e.Uri.AbsolutePath != wb.Source.AbsolutePath)
{ }
else
{
Console.WriteLine("Full Loaded");
HTMLDocument html = (HTMLDocument)wb.Document;
var value = html.getElementsByTagName("html").item(index: 0);
//do something
wb.NavigateToString(value.OuterHtml);
}
}
the event just doesn't fire (it works fine for some other sites, although).
So, what I am missing to do it?
Update 1
MCVE
XAML
<Grid>
<WebBrowser Name="wb" />
</Grid>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
wb.Navigated += Wb_Navigated;
wb.LoadCompleted += Wb_LoadCompleted;
wb.Navigate("http://aksmod.ru/skajrim-mod-kukri-ot-aksyonov-v5-0/");
}
private void Wb_LoadCompleted(object sender, NavigationEventArgs e)
{
Console.WriteLine("Loaded");
string url = e.Uri.ToString();
if (!(url.StartsWith("http://") || url.StartsWith("https://")))
{ }
if (e.Uri.AbsolutePath != wb.Source.AbsolutePath)
{ }
else
{
Console.WriteLine("Full Loaded");
HTMLDocument html = (HTMLDocument)wb.Document;
var value = html.getElementsByTagName("html").item(index: 0);
//do something
wb.NavigateToString(value.OuterHtml);
}
}
private void Wb_Navigated(object sender, NavigationEventArgs e)
{
FieldInfo fiComWebBrowser = typeof(WebBrowser)
.GetField("_axIWebBrowser2",
BindingFlags.Instance | BindingFlags.NonPublic);
if (fiComWebBrowser == null) return;
object objComWebBrowser = fiComWebBrowser.GetValue(wb);
if (objComWebBrowser == null) return;
objComWebBrowser.GetType().InvokeMember(
"Silent", BindingFlags.SetProperty, null, objComWebBrowser,
new object[] { true });
Console.WriteLine("Navigated");
}
}
The ads are embedded as iFrame within the page you presented. In my case, the Ad URL loaded in the iFrame is something like https://cdn.254a.com/images/hosted/elv/retargeting/v5/728x90.html?... (check with web browser's inspector tool)
Probably the ad does not allow iframing in your page (Check what the ad returns in X-Frame-Options header field). If this is the issue, it should be possible to implement a proxy for the ad, and let the proxy change the X-Frame-Options header.
In this case, if the ad URL is https (and not just http), you'd need to create a proxy that acts as Man-in-the-Middle. See accepted answer of What's the point of the X-Frame-Options header?. But you could replace the URL by your proxy URL, with the original URL in the ARGS. the proxy acts as HTTPS client, gets the content, proxy is able to modify the header, and returns the content to your page just via HTTP.
You can use: http://html-agility-pack.net for manipulate the Html code on C#.
I have this Windows Phone Page where I load data through the standard ViewModel scope.
public Profile()
{
InitializeComponent();
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
This works fine. However when I navigate to this page from some other page the data is still the same. I mean the LoadData() method should recheck updated data right? Please suggest.
EDIT:
My PersonalizedViewModelClass:
public class PersonalizationViewModel: INotifyPropertyChanged
{
public PersonalizationViewModel()
{
this.favorites = new ObservableCollection<ItemViewModel>();
this.Bar = new ObservableCollection<Bars>();
}
public ObservableCollection<ItemViewModel> favorites { get; private set; }
public ObservableCollection<Bars> Bar { get; private set; }
private string _sampleProperty = "Sample Runtime Property Value";
public string SampleProperty
{
get
{
return _sampleProperty;
}
set
{
if (value != _sampleProperty)
{
_sampleProperty = value;
NotifyPropertyChanged("SampleProperty");
}
}
}
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public async void LoadData()
{
favorites.Clear();
try
{
var query = ParseObject.GetQuery("Favorite")
.WhereEqualTo("user", ParseUser.CurrentUser.Username);
IEnumerable<ParseObject> results = await query.FindAsync();
this.favorites.Clear();
foreach (ParseObject result in results)
{
string venue = result.Get<string>("venue");
string address = result.Get<string>("address");
string likes = result.Get<string>("likes");
string price = result.Get<string>("price");
string contact = result.Get<string>("contact");
this.favorites.Add(new ItemViewModel { LineOne=venue, LineTwo=address, LineThree=likes, Rating="", Hours="", Contact=contact, Price=price, Latitude="", Longitude="" });
}
if (favorites.Count == 0)
{
// emailPanorama.DefaultItem = emailPanorama.Items[1];
MessageBox.Show("You do not have any saved cafes. Long press a cafe in main menu to save it.");
}
}
catch (Exception exc)
{
MessageBox.Show("Data could not be fetched!", "Error", MessageBoxButton.OK);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Implementation of PersonalizedViewModel:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await App.PersonalizedViewModel.LoadData();
user_tb.Text = ParseUser.CurrentUser.Username;
if (NavigationContext.QueryString.ContainsKey("item"))
{
var index = NavigationContext.QueryString["item"];
var indexParsed = int.Parse(index);
mypivot.SelectedIndex = indexParsed;
}
if (NavigationService.BackStack.Any())
{
var length = NavigationService.BackStack.Count() - 1;
var i = 0;
while (i < length)
{
NavigationService.RemoveBackEntry();
i++;
}
}
}
I don't see the problem, however, I think you need to narrow in on the problem.
First off, you are calling LoadData from 2 places. 1 from MainPage_Load and 1 from OnNavigatedTo. In MainPage_Load it is conditional and in OnNavigatedTo it is always being called. I suggest that you get to a single path through the code instead of 2 so that you don't get different experiences. I personally recommend (without knowing all the details) that you call load data from OnNavigatedTo instead of MainPage_Load. If you want to do it conditionally that is fine but if you are loading the data from memory, it really is unnecessary as you won't improve performance anymore than a few milliseconds. Also, if you are not loading from memory, you may not want to load it conditionally because the underlying data may have changed. In either case, the choice to load data or not should be moved out of the view and into the data layer (but that is for another post).
Once you have a single path chosen (i.e. calling LoadData from MainPage_Load or OnNavigatedTo) you should use your debugger. Put a break point in LoadData method and if it is being called appropriately, then your problem is more specific than your posted question. Here are some questions to think about (you may want to start from the last question and work your way backward)
Questions:
Is LoadData being called appropriately?
Does ParseObject have the correct data?
Is the ParseUser...UserName set properly?
Is the foreach being executed the proper # of times (i.e. does the result of your query have the right # of items?)
Couple Code Tips completely unrelated to this problem:
Single Path through code. Don't call LoadData from more than one place.
Don't call favorites.clear() twice in the same method. (it is called twice in LoadData)
Consistent naming. favorites is lowercase but Bar is upper case.
User proper data types. On your ItemViewModel you have Hours, Latitude, and Longitude. You have them as strings. These clearly are not strings. Also, you should not set them to empty. Empty means they have been set to a value. Emtpy is a valid value. Null means not set. To keep your objects clean and accurate you want to be accurate in how you set things and then deal appropriately with the impact. If you really really want them to be initialized to empty strings, then at least do it in the constructor of ItemViewModel so that every caller doesn't have to know how to initialize every property. I guarantee this is leading to buggy code if you continue using this practice.
Please take the comments as constructive criticism not criticism. I know many people don't like to hear these things but the teams I lead write bugs until they start following these types of guidelines.
Good luck,
Tom
Instead of defining this
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
into constructor i.e. Profile I would suggest remove this code from Constructor and add it into your OnNavigatedTo. so the data will load after navigation
Your OnNavigatedTo Method looks like follows
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
Might be your problem will solve.
Edit
Try this query
var results = (from find in ParseObject.GetQuery("Favorite").WhereEqualTo("user", ParseUser.CurrentUser.Username) select find);
Tried this:
var query = from favorite in ParseObject.GetQuery("Favorite")
where favorite.Get<string>("user") == ParseUser.CurrentUser.Username
select favorite;
IEnumerable<ParseObject> results = await query.FindAsync();
I had a similar Problem.All u want to do here is generate a new instance of the Page.U can do this in two Ways.
One Way is by forcing a GUID along with Page Navigation URI that will create a New Instance of the Page and your Load Data() will work.
NavigationService.Navigate(new Uri(String.Format("/MainPage.xaml?item={0}", Guid.NewGuid().ToString()), UriKind.RelativeOrAbsolute));
The Second Way to implement that Part of your Page in a User Control .Like create a User Control for Load Data() and put it in constructor.It will generate a new Instance everytime you load the Page.
If the problem persists in the front end,you can try this.
1.have you mentioned the below attribute in your xaml page?
<UserControl Loaded="MainPage_Loaded">
So that every time the page loads the data will get loaded on to the page.
2.The data must exist, if you have no problem in the code behind as it is a WPF application and not a web page.
Hope you find it useful.
Two changes required..
Remove the this.Loaded from OnNavigatedTo. That may not be required.
Second move the LoadData to OnNavigatedTo method
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
// this.Loaded += new RoutedEventHandler(MainPage_Loaded);
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
For the purpose of debugging, you can remove the line if (!App.PersonalizedViewModel.IsDataLoaded) and try.
I have a simple question in asp.net.
I want to know if it is possible to get data from controls in my user control directly . I want to do it without using Session variable,Viewstate ...
EDIT: I now use the method of declaring public variables in the UC.
Here is a part of Page_load from my parent page:
this.plan_action = (UCPlan)Page.LoadControl("~/Association/UCPlan.ascx");
PlaceHolder1.Controls.Add(this.plan_action);
if (this.plan_action.Validate == true)
{
CheckBox1.Checked = true;
//String référence = Session["liste_action"].ToString();
for (int i = 0; i < this.plan_action.List1.Count; i++)
{
Label8.Text += this.plan_action.List1[i].Référence + "/";
//Label8.Text += "/";
}
}
but my variable validate stay to false.
Here is the code where I change the value of the validate variable with it declaration:
private bool validate;
public bool Validate
{
get { return validate; }
set { validate = value; }
}
protected void Button2_Click(object sender, EventArgs e)
{
//myCommand.Connection = myConnection;
//Session["liste_action"] = this.List;
this.Validate = true;
//Response.Redirect("../Risques_folder/AjouterRisque.aspx");
}
Thank you for your help,
Quentin
UPDATE due to new information
You need to learn about the sequence of events in ASP.NET.
The Load of the page happens a long time before the Click handler of Button2 in your UserControl... so the Validate property is always going to be set to false.
You have two obvious options (as I see it)...
Keep the creation of the UserControl in your Page_Load (or preferably, move it to your Page_Init, as this is normally the most appropriate place for it). Then place your check for the Validate property in a Page_PreRender.
Or, create an Event in your UserControl, Raise that event on the click of Button2, and handle the event in the Page.
ANOTHER UPDATE
For the 2nd of the two options above, in your UserControl class have the following...
public delegate void ButtonClickedDelegate(object sender, EventArgs e);
public event ButtonClickedDelegate ButtonClicked;
In the Button2_Click method of the UserControl (after setting the this.Validate = true;) call...
ButtonClickedDelegate(sender, e);
In the Page_Init of the Page, put something like...
ctrl1.ButtonClicked += new UCPlan.ButtonClickedDelegate(ctrl1_ButtonClicked);
And then have a new method called something like
void ctrl1_ButtonClicked(object sender, EventArgs e)
{
if (ctrl1.Validate)
{
...
}
}
Remember, as you control the delegate you can pass whatever information you want, including an entire class. So instead of calling the Validate property, create a new instance of the class you want, and pass that as a delegate parameter.
You can find more information on delegates and events on MSDN.
ORIGINAL ANSWER
Unless I've missed something, this is a very simple ASP.NET concept...
You can create properties and/or methods.
For example, as a property...
public string MyProperty
{
get { return "My Property Value"; }
}
Or as a method
public string MyMethod()
{
return "My Method Value";
}
If you're talking about passing the values between the UserControl and the ASP.NET Page that contains it, then in your Page, you can simply call the property or method. If your control was called (for example) myCtrl, then you can something like...
string prop = myCtrl.MyProperty;
string meth = myCtrl.MyMethod();
(On the back of the great comment from AHMED EL-HAROUNY)
If you're talking about passing the values to the client side page, then you can use the same properties / methods directly in the HTML markup. However, in this case, the properties / method can be declared as protected rather than public
For instance, to display the value...
<%=MyProperty%>
Or
<%=MyMethod()%>
Or if you're going to use the value in javascript, something like...
var myProp = "<%=MyProperty%>";
Yes That is possible, But exposing the controls in the UserControl as Public.
I have two ajaxtoolkit file ulopads on the same page like
<ajaxToolkit:AjaxFileUpload
id="AjaxFileUpload1"
AllowedFileTypes="jpg,jpeg,gif,png"
OnUploadComplete="ajaxUpload2_OnUploadComplete"
runat="server" />
<ajaxToolkit:AjaxFileUpload
id="ajaxUpload1"
AllowedFileTypes="jpg,jpeg,gif,png"
OnUploadComplete="ajaxUpload1_OnUploadComplete"
runat="server" />
and code behind
protected void ajaxUpload2_OnUploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
string filePath = "~/Images/" + e.FileName;
filePath = filePath.Split('\\').Last();
Session["img2"] = filePath.ToString();
AjaxFileUpload1.SaveAs(MapPath(filePath));
}
protected void ajaxUpload1_OnUploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
string filePath = "~/Images/" + e.FileName;
filePath = filePath.Split('\\').Last();
Session["img1"] = filePath.ToString();
ajaxUpload1.SaveAs(MapPath(filePath));
}
The question is whenever I use upload AjaxFileUpload1 it works on and calls void ajaxUpload2_OnUploadComplete method but if I use ajaxUpload1 the method ajaxUpload2_OnUploadComplete is called again but the method ajaxUpload1 is not called
Why??
Thanks.
We got the same problem yesterday and we found out that you cannot have more than one instance of AjaxFileUpload on the same page.
If you look at the source code, you'll see that this control use a constant GUID to identify its events. Since the GUID is a constant, all instances of AjaxFileUpload use the same GUID...
Result :
the first instance swallow all the events...
Here is the GUID in action :
private const string ContextKey = "{DA8BEDC8-B952-4d5d-8CC2-59FE922E2923}";
(...)
if (this.Page.Request.QueryString["contextkey"] == ContextKey && this.Page.Request.Files.Count > 0)
We customized the September 2012 toolkit as follows - hope this is a temporary workaround and that this is fixed in a future release:
OLD
private const string ContextKey = "{DA8BEDC8-B952-4d5d-8CC2-59FE922E2923}";
NEW
private string ContextKey = "";
OLD
public AjaxFileUpload()
: base(true, HtmlTextWriterTag.Div)
{
}
NEW
public AjaxFileUpload()
: base(true, HtmlTextWriterTag.Div)
{
if (HttpContext.Current.Items["lastAjaxFileUploadContextKey"] == null)
{
HttpContext.Current.Items["lastAjaxFileUploadContextKey"] = 1;
}
else
{
HttpContext.Current.Items["lastAjaxFileUploadContextKey"] = (int)HttpContext.Current.Items["lastAjaxFileUploadContextKey"] + 1;
}
ContextKey = HttpContext.Current.Items["lastAjaxFileUploadContextKey"].ToString();
}
There actually is a way to use multiple AjaxFileUpload controls on a single page, with each control firing its own event. The solution is very simple; it involves overriding one of Microsoft's client-side functions for the AjaxFileUpload control to inject information on the control that actually caused the upload complete event, then using a single event handler for all of the AjaxFileUpload controls as a "switchboard", which will subsequently fire the correct event handler for the control which created the event server-side.
Here's how to do it:
Add this script block somewhere after the head element of your page. If you're using master pages, put this in a placeholder for HTML content:
<script type="text/javascript">
Sys.Extended.UI.AjaxFileUpload.Control.prototype.doneAndUploadNextFile = function (c) {
var a = new XMLHttpRequest, b = this;
a.open("POST", "?contextKey=" + this._contextKey + "&done=1&guid=" + c._id + "&uplCtrlID=" + b.get_id(), true);
a.onreadystatechange = function () {
if (a.readyState == 4) if (a.status == 200) {
b.raiseUploadComplete(Sys.Serialization.JavaScriptSerializer.deserialize(a.responseText));
b._processor.startUpload()
}
else {
b.setFileStatus(c, "error", Sys.Extended.UI.Resources.AjaxFileUpload_error);
b.raiseUploadError(a);
throw "error raising upload complete event and start new upload";
}
};
a.send(null);
}
</script>
This code is the same function being used to call your page and trigger the UploadComplete event, only modified to add an extra parameter - uplCtrlID - which will contain the ID of the control that REALLY caused the event.
Set up your server side code as follows:
//set the OnUploadComplete property on all of your AjaxFileUpload controls to this method
protected void anyUploader_UploadComplete(object sender, AjaxFileUploadEventArgs e)
{
//call the correct upload complete handler if possible
if (Request.QueryString["uplCtrlID"] != null)
{
//uplCtrlID (the query string param we injected with the overriden JS function)
//contains the ID of the uploader.
//We'll use that to fire the appropriate event handler...
if (Request.QueryString["uplCtrlID"] == FileUploaderA.ClientID)
FileUploaderA_UploadComplete(FileUploaderA, e);
else if (Request.QueryString["uplCtrlID"] == FileUploaderB.ClientID)
FileUploaderB_UploadComplete(FileUploaderB, e);
//etc (or use a switch block - whatever suits you)
}
}
protected void FileUploaderA_UploadComplete(AjaxFileUpload sender, AjaxFileUploadEventArgs e)
{
//logic here
}
protected void FileUploaderB_UploadComplete(AjaxFileUpload sender, AjaxFileUploadEventArgs e)
{
//logic here
}
You're all set. Multiple AjaxFileUpload controls on the same page, no problems.
Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers