C# Custom EventHandler - c#

i have a custom event handler in the page, and it is called by the user controls of it.
everything is fine, except there is error display in the code ( red highlighted), but the program can be compiled, and able to run with no apparent error.
but i want to fix (or understand) the reason why the visual studio showed error for that
the error is
the code is
-PAGE
Operator_agentcontrol2 agentcontrol = (Operator_agentcontrol2)Page.LoadControl("~/operator/agentcontrol2.ascx");
agentcontrol.displayLevel = (int)Common.WinLose_Level.lvChild4 + 10 + (Panel_agents.Controls.Count * 10);
agentcontrol.AppendProcess += Append_UC_Progress;//Error line
the event in the page-
public void Append_UC_Progress(object sender, EventArgs e)
{
Common.WinLose_ProgressStage wps = (Common.WinLose_ProgressStage)e;
progress.AppendProgress(wps);
SaveProgressVS();
}
-USER CONTROL
public partial class Operator_agentcontrol2 : System.Web.UI.UserControl
{
public event EventHandler<Common.WinLose_ProgressStage> AppendProcess;
}
Thanks
---Update---
I have tried to follow https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.85).aspx for the custom event handler.
but then i got this error
---Update---
Eventually I found that actually my scenario doesn't require to use something like EventHandler
i have changed the code in user control
public partial class Operator_agentcontrol2 : System.Web.UI.UserControl
{
public event EventHandler AppendProcess;
}
By doing this the error is gone, and the user control still able to call the Page's function successfully with an object Common.WinLose_ProgressStage.

As far as I can see, two errors are being reported...
1 - It cannot find a suitable overload for Append_UC_Progess (which takes a Common.WinLose_ProgressStage as an argument)
2 - The assembly containing Common.WinLose_ProgressStage is not referenced.
What I would suggest is happening, is that once it is all compiled the assembly containing Common.WinLose_ProgressStage gets pulled in (perhaps by another referenced assembly), and thus it is noticed that it inherits from EventArgs. It can therefore find a suitable overload of Append_UC_Progess and it all resolves ok.
In order to get rid of the error, I would suggest explicitly referencing the assembly containing Common.WinLose_ProgressStage, so that Visual Studio can see the inheritance tree at design time.

Related

How to show a custom user control from a Class Library in C#

I'm pretty new to programming with Class Libraries and I think my question is kind of complicated.
I'm working on my own exception logger. This exception logger has static routines and functions so I don't have to declare it in each of my other classes. (Is this btw a good idea? :/ ) Whenever something goes wrong, a routine is called in the exception logger class. This routine determines what the error message should be based on the number I passed to it.
My goal is as follow:
The exception logger should trigger an event in the GUI. The event in the GUI then shows a custom made message box with the error message in it. I know the possibility of declaring the exception logger in the GUI with WithEvents, but the there is no purpose of having everything static in the exception logger class.
EDIT 1: I'm looking for a way to trigger an event in the GUI project from a ExceptionLogger Class in a Class Library in the same solution without declaring the Class ExceptionLogger in every Class in my GUI project.
EDIT 2: Let me give an example. I have a Class Library named Base. This Class Library contains a Class named ExceptionLogger. This Class in its turn has a Static Routine called Log.
So I have a .dll named Base as a Reference in my main Project called GUI. GUI has a Form MainWindow and 2 Classes named Product and Customer.
What I want is that, for example, the class Customer runs into an Error (by using Try...Catch) and in the Catch part Base.Log(1). The Log routine in ExceptionLogger will look up what the error message has to be and will fire an event in the GUI's MainWindow showing a User Made MessageBox.
The real question is, how do I fire this event from Log into the MainWindow?
EDIT 3: The User Made MessageBox in EDIT 2 is rather a Panel that overlays the MainWindow, not a MessageBox window that opens.
I have found the solution on my own. Any remarks are welcome. Already tnx to the ppl who commented or posted an answer.
This is an example of what I was looking for and it's working.
This is my DLL (namespace Base):
public class ExceptionHandler
{
public static event EventHandler ShowErrorMessage;
public static void test(EventArgs e)
{
ShowErrorMessage("me", e);
}
}
This is the code in my MainWindow:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Base.ExceptionHandler.ShowErrorMessage += ExceptionHandler_ShowErrorMessage;
}
void ExceptionHandler_ShowErrorMessage(object sender, EventArgs e)
{
MessageBox.Show((string)sender);
}
private void Form1_Load(object sender, EventArgs e)
{
Base.ExceptionHandler.test(new EventArgs());
}
}

C# custom events doesn't want to work with forms, partial class

I'm creating an app, there is some class that does some background operations and after all is done, parent object is notified using event. To provide event functionality i use following code:
public delegate void ShopStateChangedEventHandler(object sender, QuantityManagerEventArgs ea);
public event ShopStateChangedEventHandler ShopStateChanged;
protected virtual void WhenShopStateChanged(QuantityManagerEventArgs ea)
{
if (ShopStateChanged != null)
{
ShopStateChanged(this, ea);
}
}
It was working fine in all cases while I was using this piece of code with classes I've made, today I needed to have some custom made event added to one of forms in my application. Unfortunately i'm getting build error saying that compiler was unable to find ShopStateChangedEventHandler in form that is parent to form with custom event, and error is about line that adds listener
qmgr.ShopStateChanged += new ShopStateChangedEventHandler(qmgr_ShopStateChanged);
I really have no clue where to look for source of this error while in all other classes where i use this code all works fine, i suspect is it either because fact that the class i try to add custom event inherits from Form or maybe because it is partial class. As for now im far in the woods if it comes to solving it and I have no idea how to crunch it.
I hope you could suggest me what to do, or how to alter my code to make it all work with form.
thanks in advance
mth
EDIT
error is CS2046
The type or namespace name 'type/namespace' could not be found (are you missing a using directive or an assembly reference?)
all classes and forms belong to the same namespace
and as for qmgr_ShopStateChanged for now its just empty method
void qmgr_ShopStateChanged(object sender, QuantityManagerEventArgs ea)
{
}
qmgr is instance of form that contains custom event code, qmgr and qmgr_ShopStateChanged along with code that creates listener and makes problem, belongs to main form of application (frmMain).
Declare your delegate directly on your namespace outside any class.

How to use the NavigationService.Navigate inside a CustomMessageBox Dismissed event handler?

I am using the CustomMessageBox control from the Silverlight Toolkit for Windows Phone. When passing an anonymous callback (a 'delegate' in MS speak?) as suggested in the tutorials I reference a member of the page's partial class defined in the code-behind file. This builds and deploys but crashes when I reach the logic at runtime.
I noticed from the VS debugger that the scope inside the callback only contains members from the XAML side of the page partial class and not the members from the code-behind file. This means that the member I refer to is not in the scope (even though Intellisense is fine with it). Moreover I cannot use NavigationService.Navigate inside the callback.
How do I call code within the containing class from the callback?
Here is the code,
// This is a member of the partial class which inherits from
// PhoneApplicationPage
private void cancelBtn_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if ((this.nameTextBox.Text != String.Empty) || (bool)this.protectCheckBox.IsChecked)
{
CustomMessageBox messageBox = new CustomMessageBox()
{
Caption = "Confirm leave page",
Message = "You have entered some profile data which will be lost if you leave this page. Are you sure you want to leave this page?",
LeftButtonContent = "no",
RightButtonContent = "yes"
};
messageBox.Dismissed += (s1, e1) =>
{
if (e1.Result == CustomMessageBoxResult.RightButton)
{
// Both of these raise an exception ...
GoToProfilePage();
//NavigationService.Navigate(new Uri("/View/MainPage.xaml", UriKind.Relative));
// Inspecting the debugger here shows only half the expected
// number of methods in the 'this' object - specifically only
// those defined in XAML
}
};
messageBox.Show();
}
else
{
// This works fine
GoToProfilePage();
}
}
Where GoToProfilePage() is a method in the code-behind file.
This is the exception,
System.NullReferenceException was unhandled
Message=NullReferenceException
StackTrace:
at Microsoft.Phone.Controls.CustomMessageBox.ClosePopup(Boolean restoreOriginalValues)
at Microsoft.Phone.Controls.CustomMessageBox.c__DisplayClass4.b__1(Object s, EventArgs e)
at Microsoft.Phone.Controls.Transition.OnCompleted(Object sender, EventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
Update
It looks like the code is executed, it is only when the delegate finishes that the null reference exception is raised so it may not be a problem with scope ...
OK figured it out. The latest build of the Windows Toolkit .dll (which includes CustomMessageBox) needed a reference in my solution.
Apparently there is an older version of the Windows Toolkit which is included in the default references somewhere since both ContextMenu and CustomMessageBox worked at least partially beforehand which is very confusing ...
To add the updated reference, I built the .dll from the source in a separate project and copied it to my project. I added a reference from the Reference right-click menu in VS and browsed to the file in the debug\bin directory.
A quick hack is to comment line 657 of CustomMessageBox.cs file in the toolkit source code and compile again. Then reference this new dll in your app.
...
private void ClosePopup(bool restoreOriginalValues)
{
// Remove the popup.
_popup.IsOpen = false;
//_popup = null; <-- THIS IS LINE 657
...
There is an issue posted in http://phone.codeplex.com/workitem/10575

Static event doesn't get subscribed in different dll

I have one WinForms control project that produces a dll. There is a second dll project (also winforms control) that uses the first project. There is a third winforms project, this time a form, that uses the second project. So [Third Project] <>------> [Second Project] <>--------> [First Project]
The first project exposes a static event. I'm trying to subscribe to that event from the third project. The event stays as null (not subscriptions) after the += call.
Why is it not subscribing? Is it because the Winforms controls have their own thread? The FirstProject user control is created on the fly at some point in time. But I will expect the static to work correctly, without doing anything else,
Project 1
namespace Something
{
public partial class FirstClass : UserControl
{
...
public delegate void EventHandler();
public static event EventHandler MyEvent;
...
}
}
Project 3
namespace Another
{
public partial class ThirdClass : Form
{
...
public ThirdClass()
{
....
Something.FirstClass.MyEvent += new Something.FirstClass.EventHandler(MyHandler);
}
public void MyHandler()
{
}
...
}
}
EDIT
I have created a small application with the basics to get the three projects and the static event. And it works. Therefore something else is going on.
EDIT 2
The dll that contained the first project, the one with the event, was being loaded twice. I have just added an alias, but didn't help. And still will not explain when just after the += the event is still null.
EDIT 3 I transformed the event so I have the add/remove accessors pair. It does enter into the add. The Handler method gets the value correctly (and therefore no null), but once it goes outside, is null again.
The static event should work just fine. Try to debug your code to make sure the event registration is being called and that the event itself gets fired as expected. The event does not care about threads. It will accept the registration either way. Threading will, however, cause an exception if you try to edit the form on a thread besides the UI thread.
And the reason will be in my EDIT 2. Because is a static event, loading twice the dll (two different paths) was creating two different static events (or two different handlers). My EDIT 3 clearly showed that the event was being subscribed to.
Once I forced the third project (the one subscribing to the static event) to load the dll from the same location as the project creating the event (I didn't wanted to use the GAC), all worked.

Custom User Control Not Initialized in Auto-Generated Code

This has happened many times before, but I never bothered to figure out why, and now I am tired of it:
For instance, I derive a class from RichTextBox or Panel, I rebuild my project to have the class added to the VS designer toolbox, and then I drag & drop the custom user control to a Form. Everything works fine, and I can run my project...
The problem comes when I edit properties of the Form or the custom user control through the designer. Sometimes, the designer removes the initialization line from its code-behind, causing an exception in the designer and the executable because the control remains uninitialized.
In other words, the following line is removed from say, Form1.Designer.cs:
this.customRichTextBox1=new CustomRichTextBox();
No other line is removed from the code-behind, so the attributes of the custom control are still set, although the variable stays uninitialized.
My solution has always been to manually initialize my user control in the designer code-behind, but the designer eventually removes it again.
I believe that this does not happen when I build a Custom UserControl through the designer (but I am not completely sure of this). It only happens when I define something like the following manually:
class CustomRichTextBox:RichTextBox{}
This is so annoying. What am I doing wrong?
As #Cody requested, here are the steps to reproduce the problem. I am using VS2010, but I've had this problem since 2005, I think.
Step 1. Create new Windows Forms Application, any Framework
Step 2. Add the following class below your main Form class: (It just happens that this is the control that is causing me this problem this time.)
class CustomRichTextBox : RichTextBox
{
Timer tt = new Timer();
internal CustomRichTextBox()
{
tt.Tick += new EventHandler(tt_Tick);
tt.Interval = 200;
}
protected override void OnTextChanged(EventArgs e)
{
tt.Stop();
tt.Start();
}
void tt_Tick(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Hello world!");
}
}
Step 3. Press F6 to rebuild.
Step 4. Add the CustomRichTextBox control to your Form by dragging and dropping from the Toolbox.
Step 5. If you wish, you may press F5 to test the application, but it should work. Close the running application.
Step 6. Press F6 to rebuild, and at this point, the designer should crash with the following message: "The variable 'customRichTextBox1' is either undeclared or was never assigned." (In one case, the whole VS completely crashed, but the error is usually contained within the designer.)
Step 7. To correct the issue, go into the code-behind and initialize the variable, but next time you rebuild, the initialization line will be gone.
Thanks to everyone who tried answering my question and who posted comments that helped me diagnose and solve the problem.
The problem occurs when using an "internal" keyword with the control's constructor. Changing it to "public" fixes the problem. The reason for this behavior might be that the Designer's own classes cannot see the constructor because they are not within the namespace of my class unless it is marked public. This all makes sense, and I will use the public keyword from now on.
The class does not need to be in its own individual file or be the first declared class in the file as other answers suggested.
The following class works well because the constructor's keyword was changed to public.
class CustomRichTextBox : RichTextBox
{
Timer tt = new Timer();
public CustomRichTextBox()
{
tt.Tick += new EventHandler(tt_Tick);
tt.Interval = 200;
}
protected override void OnTextChanged(EventArgs e)
{
tt.Stop();
tt.Start();
}
void tt_Tick(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Hello world!");
}
}
Is your build set to Debug or it is Release?
I suppose that it is release as I think compiler optimizes the code and remove designer generated line.
Have you tried putting the control code in its own file? I've had problems even with the form designer in the past when the designer code was not int he first class in the file.
I had a similar problem that this posted helped me solve. I have a CustomControl that extends ComboBox, that class contained an internal private class YearItem. I've tried to highlight only the code needed to understand the problem and the solution.
public class YearsCbo : ComboBox //Inherits ComboBox
{
public YearsCbo() {
fill();
}
private void fill() { // <<<=== THIS METHOD ADDED ITEMS TO THE COMBOBOX
for(int idx = 0; idx < 25; idx++) {
this.Items.Add(new YearItem());
}
}
// Other code not shown
private class YearItem {} // <<<=== The VS designer can't access this class and yet
// it generated code to try to do so. That code then fails to compile.
// The compiler error rightfully says it is unable to access
// the private class YearItem
}
I could drag/drop that control YearsCbo onto a form and it worked correctly, but after I returned and edited the form the VS designer generated code that would not compile. The offending code something like this:
Dim YearItem1 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
Dim YearItem2 As my.ns.YearsCbo.YearItem = New my.ns.YearsCbo.YearItem()
// This was repeated 25 times because in my constructor I created 25 of these
Me.YearsCbo1.Items.AddRange(New Object() {YearItem1, 2, 3, ..., YearItem25 });
Notice that the designer generated code which tried to access the private class. It didn't need to do that but for some reason it did.
Through trial and error, and this post: How to tell if .NET code is being run by Visual Studio designer came up with a solution:
I added a property to tell if I am running in the designer.
public bool HostedDesignMode
{
get
{
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
return true;
else
return false;
}
}
I also changed the constructor so that it doesn't call fill() so when the designer runs, there are no items in the ComboBox so the designer doesn't feel the need to manually create those items.
The "fixed" code is shown below:
public class YearsCbo : ComboBox //Inherits ComboBox
{
public YearsCbo() {
if ( ! HostedDesignMode ) {
fill();
}
}
private class YearItem {} // <<<=== Now the VS Designer does not try to access this
}
This code was written using VS2012 Premium on Win7x64 OS (in case it matters).

Categories

Resources