How to call this method? - c#

i'm just a newbie in programming and i made a function, just one stupid problem and a very stupid question.Please don't rude, How do i call this function from a different form or class. or even in the same form
public void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
for (int i = 0; i <= dtInfo.Rows.Count - 2;i++ )
{
Battery = Convert.ToDateTime(dtInfo.Rows[i].Cells[5].Value.ToString());
Oil = Convert.ToDateTime(dtInfo.Rows[i].Cells[14].Value.ToString());
Fran = Convert.ToDateTime(dtInfo.Rows[i].Cells[12].Value.ToString());
lastkm = int.Parse(dtInfo.Rows[i].Cells[13].Value.ToString());
batt = Battery - DateTime.Now;
doil = Oil - DateTime.Now;
dfran = Fran - DateTime.Now;
if (batt.Days <= 7)
{
dtInfo.Rows[i].Cells[5].Style.BackColor = Color.Green;
}
if (doil.Days <= 7)
{
dtInfo.Rows[i].Cells[14].Style.BackColor = Color.Green;
}
if (dfran.Days <= 7)
{
dtInfo.Rows[i].Cells[12].Style.BackColor = Color.Green;
}
if (lastkm <= 500)
{
dtInfo.Rows[i].Cells[13].Style.BackColor = Color.Green;
}
}
}
EDITED
when i first open my form the color change then when i reopen it
it wont change but when i trace the code the value of the color was change but not the color in the cell

That's an event handler, and you can't raise the event yourself unless:
The class exposes a protected (or even public) method to fire it directly, but that doesn't happen usually in the .NET classes.
You trigger it by doing what the actual event represents -- In your case, when the databinding between your grid and your source is complete.
You can call that method, though, but it wouldn't have any relevant meaning, since you wouldn't raise the event. Still, if the event logic doesn't matter and you just want that code to execute, you can do it through:
dataGridView1_DataBindingComplete(null, null);
But in that case, you can just wrap that method's content in a simple method with a returning type of void and no parameters.

dataGridView1_DataBindingComplete() is just a plain old method
dataGridView1_DataBindingComplete(this, new RoutedEventArs());
Should do the trick if you want to call it from the same object.
if you want to reuse that section of code I would take everything within the method and create a separate public method so you can call it from other places and from other objects.

It all depends where the function is located. If you have it under the same class as your form, you can just call it in the same scope. But from what I see, this is a event handler, and you shouldn't need to call it, as it handles the dataGridView event "DataBindingComplete". For more info about it, visit this.
However if you need to call it for some reason you can just do:
dataGridView1_DataBindingComplete(null, null)

Related

WinForm C# how attach an Method to a Control programmaticaly created

In my apps, I generated a bunch of DataGridView programmaticaly. I can add/remove rows to it and retrieve all the data from it and copy the data in another DataGrid.
for instance when Im creating it
public void Example(TabControl tab)
for(int i=0;i<tab.TabCount;i++)
{
tab.TabPages.Add("Panneau " + tab.TabCount);
DataGridView panGridView = new DataGridView();
panGridView.Name = "panGridView_" + tab.TabCount;
panGridView.Location = new System.Drawing.Point(0, 0);
panGridView.RowTemplate.Height = 24;
panGridView.Size = new System.Drawing.Size(1375, 458);
panGridView.Columns.Add("id", "id");
panGridView.Columns.Add("part_code", "part_code");
panGridView.Columns[0].Width = 100;
panGridView.Columns[1].Width = 150;
panGridView.Visible = true;
panIndex.Items.Add(tab.TabCount - 1);
tab.TabPages[tab.TabCount - 1].Controls.Add(panGridView);
}
Now, I want to attach Method to this Control. I think the best way would be to attach it when I initialize the Control. For example I would attach a Method like this one
public void Action(DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
I tried a lot of this but cant figure out how do it.
Thanks
It seems to me that you want a special kind of DataGridView. You want a DataGridView with an attached method. You've learned, whenever you need a "class, very similar to another class, but with just a small thing different", you need to create a derived class, or make a composition, if you don't want to expose all methods of the base class.
class DataGridViewWithAttachedMethod : DataGridView // TODO: invent proper name
{
...
}
class MySpecialDataGridView : UserControl
{
private DataGridView dgv1;
...
}
The advantage of the first method is that users of your class (= code, not operators) have access to all DataGridView methods, so it will be very flexible to use. Disadvantage: they have access to all DataGridView methods, so they can mess up your DataGridView.
Whether you will use derivation or composition depends on how fool proof your class needs to be, in other words: do you want to expose methods that you prefer not to be used by others?
I want to attach Method to this Control.
This is not really clear. Do you want to give DataGridView an extra method, always the same one? Or do you want to Dynamically attach a method: dgv1 has another attached method than dgv2.
class DgvWithExtraMethod : ...
{
public void Action(DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
}
All instances of this dgv will have the same extra method. All you have to do is create an object of this class, and you will have this method.
However, if you want to attach different methods to instances of the class, you need a property that contains this method.
class DgvWithMethod : ...
{
public Action<DataGridViewCellMouseEventArgs> ExtraMethod {get; set;}
}
If you want your class fool proof, consider to initialize the method with a "no operation (NOP)"
private static Action<DataGridViewCellMouseEventArgs> NOP = (e) => {};
public Action<DataGridViewCellMouseEventArgs> ExtraMethod {get; set;} = NOP;
Usage:
DgvWithMethod dgv1 = new DgvWithMethod
{
ExtraMethod = (e) =>
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
}
This is the exact answer to your question. However, what I think that you want to know is: if the operator click on row 2, then I want to execute method F(), and if he clicks on row 3, I want to execute method G(), etc
If that is what you want, use visual studio designer to add an event handler on DataGridView.CellMouseClick, or if you want to reuse this class (derivation / composition) override DataGridView.OnCellMouseClick.
private void DataGridView1_CellMouseClick(Object sender,
DataGridViewCellMouseEventArgs e)
{
// find out which column is clicked
switch (e.ColumnIndex)
{
case 0: // column Id clicked
this.ProcessColumnIdClick(e);
break;
case 1: // column Name clicked
this.ProcessColumnNameClick(e);
break;
...
Take care though: if you allow column reordering, you should compare ColumnIndex with the DisplayIndex of each column.
if (e.ColumnIndex == this.columnId.DisplayIndex)
this.ProcessColumnIdClick(e);
else if (e.ColumnIndex == this.columnName.DisplayIndex)
...
Like #CurleD stated, you simply subscribe your method to specific EventHandler. So change your Action to this:
private void panGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
and then subscribe to the CellMouseClick event:
panGridView.CellMouseClick += panGridView_CellMouseClick;

Creating custom Label in C# and passing data in events

I had been playing around with an idea for a game, and implementation was going fairly well, but I have hit a stumbling block.
Basically, I have a form, which will show talent trees. I am just going to use labels to display the relevant details, and I want to create them programmatically. The display part is working fine, the part I am having trouble with is adding an event handler to the labels.
I want to be able to pass data during the event handling, so that I can identify which specific label was clicked, but I am hitting a brick wall. So when a particular label is clicked, the name of its associated skill (just passing a string) will be sent to the event handler. Any help would be appreciated. Here is the relevant code that I have:
public void DisplayTree()
{
int i=0;
startPoint.X = 40;
startPoint.Y = 125;
foreach(SkillNode s in tree.tier1)
{
for (i=0; i < s.labels.Count;i++ )
{
//Displays a label for each available rank for a skill
s.labels.ElementAt(i).Text = (i+1).ToString()+"/"+s.maxRank.ToString();
s.labels.ElementAt(i).Location = startPoint;
startPoint.Y += s.labels.ElementAt(i).Height + 2;
s.labels.ElementAt(i).Name = "lbl"+s.name+i.ToString();
//Only enable it to be clicked if the user is at the correct rank
if (s.rank == i)
{
s.labels.ElementAt(i).Enabled = true;
}
else
{
s.labels.ElementAt(i).Enabled = false;
}
//Add Event here
//I want to pass the name of the skill with the event
this.Controls.Add(s.labels.ElementAt(i));
}
startPoint.X += s.title.Width + 5;
startPoint.Y = 125;
}
}
public void LabelClick()
{
//Code here to pick out the name of the label
}
Try this:
public void LabelClick()
{
Console.WriteLine(((Control)sender).Name);
}
When you create an event and want to follow the official C# styleguide, you follow the following pattern:
public delegate void {YourName}EventHandler(object sender, {YourName}EventArgs args);
public event {YourName}EventHandler EventName;
Every information about what happened in the event or can be manipulated by the subscriber is stored in a class that inherits EventArgs. The delegate also contains a reference to the sender, which is the object that fires the event.
When you fire an event you do the following, regularly in a protected method that has the same name as the Event with an "On" as prefix:
EventName?.Invoke(this, new {YourName}EventArgs() { Initialize Stuff });
As you can see, you can work with the sender and identify the object. In your case you could also change object sender to UIElement sender (or similar) to make it easier to identify stuff without a cast.

Temporarily stop form events from either being raised or being handled?

I have a ton on controls on a form, and there is a specific time when I want to stop all of my events from being handled for the time being. Usually I just do something like this if I don't want certain events handled:
private bool myOpRunning = false;
private void OpFunction()
{
myOpRunning = true;
// do stuff
myOpRunning = false;
}
private void someHandler(object sender, EventArgs e)
{
if (myOpRunning) return;
// otherwise, do things
}
But I have A LOT of handlers I need to update. Just curious if .NET has a quicker way than having to update each handler method.
You will have to create your own mechanism to do this. It's not too bad though. Consider adding another layer of abstraction. For example, a simple class called FilteredEventHandler that checks the state of myOpRunning and either calls the real event handler, or suppresses the event. The class would look something like this:
public sealed class FilteredEventHandler
{
private readonly Func<bool> supressEvent;
private readonly EventHandler realEvent;
public FilteredEventHandler(Func<bool> supressEvent, EventHandler eventToRaise)
{
this.supressEvent = supressEvent;
this.realEvent = eventToRaise;
}
//Checks the "supress" flag and either call the real event handler, or skip it
public void FakeEventHandler(object sender, EventArgs e)
{
if (!this.supressEvent())
{
this.realEvent(sender, e);
}
}
}
Then when you hook up the event, do this:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
When WhateverEvent gets raised, it will call the FilteredEventHandler.FakeEventHandler method. That method will check the flag and either call, or not call the real event handler. This is pretty much logically the same as what you're already doing, but the code that checks the myOpRunning flag is in only one place instead of sprinkled all over your code.
Edit to answer question in the comments:
Now, this example is a bit incomplete. It's a little difficult to unsubscribe from the event completely because you lose the reference to the FilteredEventHandler that's hooked up. For example, you can't do:
this.Control.WhateverEvent += new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler;
//Some other stuff. . .
this.Control.WhateverEvent -= new FilteredEventHandler(() => myOpRunning, RealEventHandler).FakeEventHandler; //Not gonna work!
because you're hooking up one delegate and unhooking a completely different one! Granted, both delegates are the FakeEventHandler method, but that's an instance method and they belong to two completely different FilteredEventHandler objects.
Somehow, you need to get a reference to the first FilteredEventHandler that you constructed in order to unhook. Something like this would work, but it involves keeping track of a bunch of FilteredEventHandler objects which is probably no better than the original problem you're trying to solve:
FilteredEventHandler filter1 = new FilteredEventHandler(() => myOpRunning, RealEventHandler);
this.Control.WhateverEvent += filter1.FakeEventHandler;
//Code that does other stuff. . .
this.Control.WhateverEvent -= filter1.FakeEventHandler;
What I would do, in this case, is to have the FilteredEventHandler.FakeEventHandler method pass its 'this' reference to the RealEventHandler. This involves changing the signature of the RealEventHandler to either take another parameter:
public void RealEventHandler(object sender, EventArgs e, FilteredEventHandler filter);
or changing it to take an EventArgs subclass that you create that holds a reference to the FilteredEventHandler. This is the better way to do it
public void RealEventHandler(object sender, FilteredEventArgs e);
//Also change the signature of the FilteredEventHandler constructor:
public FilteredEventHandler(Func<bool> supressEvent, EventHandler<FilteredEventArgs> eventToRaise)
{
//. . .
}
//Finally, change the FakeEventHandler method to call the real event and pass a reference to itself
this.realEvent(sender, new FilteredEventArgs(e, this)); //Pass the original event args + a reference to this specific FilteredEventHandler
Now the RealEventHandler that gets called can unsubscribe itself because it has a reference to the correct FilteredEventHandler object that got passed in to its parameters.
My final advice, though is to not do any of this! Neolisk nailed it in the comments. Doing something complicated like this is a sign that there's a problem with the design. It will be difficult for anybody who needs to maintain this code in the future (even you, suprisingly!) to figure out the non-standard plumbing involved.
Usually when you're subscribing to events, you do it once and forget it - especially in a GUI program.
You can do it with reflection ...
public static void UnregisterAllEvents(object objectWithEvents)
{
Type theType = objectWithEvents.GetType();
//Even though the events are public, the FieldInfo associated with them is private
foreach (System.Reflection.FieldInfo field in theType.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance))
{
//eventInfo will be null if this is a normal field and not an event.
System.Reflection.EventInfo eventInfo = theType.GetEvent(field.Name);
if (eventInfo != null)
{
MulticastDelegate multicastDelegate = field.GetValue(objectWithEvents) as MulticastDelegate;
if (multicastDelegate != null)
{
foreach (Delegate _delegate in multicastDelegate.GetInvocationList())
{
eventInfo.RemoveEventHandler(objectWithEvents, _delegate);
}
}
}
}
}
You could just disable the container where all these controls are put in. For example, if you put them in a GroupBox or Panel simply use: groupbox.Enabled = false; or panel.Enabled = false;. You could also disable the form From1.Enabled = false; and show a wait cursor. You can still copy and paste these controls in a container other than the form.

Get data from user control since Webpage

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.

How do I safely populate with data and Refresh() a DataGridView in a multi-threaded application?

My app has a DataGridView object and a List of type MousePos. MousePos is a custom class that holds mouse X,Y coordinates (of type "Point") and a running count of this position. I have a thread (System.Timers.Timer) that raises an event once every second, checks the mouse position, adds and/or updates the count of the mouse position on this List.
I would like to have a similar running thread (again, I think System.Timers.Timer is a good choice) which would again raise an event once a second to automatically Refresh() the DataGridView so that the user can see the data on the screen update. (like TaskManager does.)
Unfortunately, calling the DataGridView.Refresh() method results in VS2005 stopping execution and noting that I've run into a cross-threading situation.
If I'm understanding correctly, I have 3 threads now:
Primary UI thread
MousePos List thread (Timer)
DataGridView Refresh thread (Timer)
To see if I could Refresh() the DataGridView on the primary thread, I added a button to the form which called DataGridView.Refresh(), but this (strangely) didn't do anything. I found a topic which seemed to indicate that if I set DataGridView.DataSource = null and back to my List, that it would refresh the datagrid. And indeed this worked, but only thru the button (which gets handled on the primary thread.)
So this question has turned into a two-parter:
Is setting DataGridView.DataSource to null and back to my List an acceptable way to refresh the datagrid? (It seems inefficient to me...)
How do I safely do this in a multi-threaded environment?
Here's the code I've written so far (C#/.Net 2.0)
public partial class Form1 : Form
{
private static List<MousePos> mousePositionList = new List<MousePos>();
private static System.Timers.Timer mouseCheck = new System.Timers.Timer(1000);
private static System.Timers.Timer refreshWindow = new System.Timers.Timer(1000);
public Form1()
{
InitializeComponent();
mousePositionList.Add(new MousePos()); // ANSWER! Must have at least 1 entry before binding to DataSource
dataGridView1.DataSource = mousePositionList;
mouseCheck.Elapsed += new System.Timers.ElapsedEventHandler(mouseCheck_Elapsed);
mouseCheck.Start();
refreshWindow.Elapsed += new System.Timers.ElapsedEventHandler(refreshWindow_Elapsed);
refreshWindow.Start();
}
public void mouseCheck_Elapsed(object source, EventArgs e)
{
Point mPnt = Control.MousePosition;
MousePos mPos = mousePositionList.Find(ByPoint(mPnt));
if (mPos == null) { mousePositionList.Add(new MousePos(mPnt)); }
else { mPos.Count++; }
}
public void refreshWindow_Elapsed(object source, EventArgs e)
{
//dataGridView1.DataSource = null; // Old way
//dataGridView1.DataSource = mousePositionList; // Old way
dataGridView1.Invalidate(); // <= ANSWER!!
}
private static Predicate<MousePos> ByPoint(Point pnt)
{
return delegate(MousePos mPos) { return (mPos.Pnt == pnt); };
}
}
public class MousePos
{
private Point position = new Point();
private int count = 1;
public Point Pnt { get { return position; } }
public int X { get { return position.X; } set { position.X = value; } }
public int Y { get { return position.Y; } set { position.Y = value; } }
public int Count { get { return count; } set { count = value; } }
public MousePos() { }
public MousePos(Point mouse) { position = mouse; }
}
You have to update the grid on the main UI thread, like all the other controls. See control.Invoke or Control.BeginInvoke.
UPDATE! -- I partially figured out the answer to part #1 in the book "Pro .NET 2.0 Windows Forms and Customer Controls in C#"
I had originally thought that Refresh() wasn't doing anything and that I needed to call the Invalidate() method, to tell Windows to repaint my control at it's leisure. (which is usually right away, but if you need a guarantee to repaint it now, then follow up with an immediate call to the Update() method.)
dataGridView1.Invalidate();
But, it turns out that the Refresh() method is merely an alias for:
dataGridView1.Invalidate(true);
dataGridView1.Update(); // <== forces immediate redraw
The only glitch I found with this was that if there was no data in the dataGridView, no amount of invalidating would refresh the control. I had to reassign the datasource. Then it worked fine after that. But only for the amount of rows (or items in my list) -- If new items were added, the dataGridView would be unaware that there were more rows to display.
So it seems that when binding a source of data (List or Table) to the Datasource, the dataGridView counts the items (rows) and then sets this internally and never checks to see if there are new rows/items or rows/items deleted. This is why re-binding the datasource repeatedly was working before.
Now to figure out how to update the number of rows to display in dataGridView without having to re-bind the datasource... fun, fun, fun! :-)
After doing some digging, I think I have my answer to part #2 of my question (aka. safe Multi-threading):
Rather than using System.Timers.Timer, I found that I should be using System.Windows.Forms.Timer instead.
The event occurs such that the method that is used in the Callback automatically happens on the primary thread. No cross-threading issues!
The declaration looks like this:
private static System.Windows.Forms.Timer refreshWindow2;
refreshWindow2 = new Timer();
refreshWindow2.Interval = 1000;
refreshWindow2.Tick += new EventHandler(refreshWindow2_Tick);
refreshWindow2.Start();
And the method is like this:
private void refreshWindow2_Tick(object sender, EventArgs e)
{
dataGridView1.Invalidate();
}
Looks like you have your answer right there!
Just in cawse you're curious about how to do cross thread calls back to ui:
All controls have a Invoke() method (or BEginInvoke()- in case you want to do things asynchronously), this is used to call any method on the control within the context of the main UI thread.
So, if you were going to call your datagridview from another thread you would need to do the following:
public void refreshWindow_Elapsed(object source, EventArgs e)
{
// we use anonymous delgate here as it saves us declaring a named delegate in our class
// however, as c# type inference sometimes need a bit of 'help' we need to cast it
// to an instance of MethodInvoker
dataGridView1.Invoke((MethodInvoker)delegate() { dataGridView1.Invalidate(); });
}

Categories