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

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

Related

C# Custom EventHandler

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.

Running an exe converted to a dll from another exe

I have a completely functioning application that I have converted to a Dll.
I need to be able to run that application (now dll) out of an exe . Ive added the dll as a reference to the new exe and have tried to just instantiate a frmMain object from the namespace used in the dll and show it like I would in any other application.
However, I get a bunch of null reference exceptions in several of the references that I had in the exe that I converted to a dll.
I've also tried the solution here Launch Dll using C# program
and tried jumping to the Program.cs Main() function at which point I get a "SetCompatibleTextRenderingDefault must be called before the first IWin32Window object is created in the application." error.
Here is the dll's program.cs
namespace VTRS
{
class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
//had to add this because exe can't find Main
public void invokeMain()
{
Main();
}
//you have to have a constructor for the exe to instantiate this class
public Program()
{
}
}
}
and here is the new applications code
private void button1_Click(object sender, EventArgs e)
{
try
{
System.Reflection.Assembly dll1 = System.Reflection.Assembly.LoadFile(Application.StartupPath + "\\VTRSTCACodeMaintenance.dll");
if (dll1 != null)
{
object obj = dll1.CreateInstance("VTRS.Program");
if (obj != null)
{
System.Reflection.MethodInfo mi = obj.GetType().GetMethod("invokeMain");
mi.Invoke(obj, new object[0]);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Can anyone explain to me why this doesn't work or point me in the right direction? I'm super confused and am not doing this by choice (I'm being told to by the boss)
You do not need reflection, nor do you need to execute the Main() method of your original .exe file (indeed, you should probably just remove it, if that project is intended to just be a plain DLL).
You don't need reflection because, once you've added the assembly as a reference in your new project, all of the public types and members are accessibly in your new project. Just make sure you've declared frmMain as public (this is the default in Visual Studio, so it may already be public). Then instead of all that reflection rigmarole, all you need to do is what you'd normally do to show a form:
frmMain form = new frmMain();
form.Show();
or even just:
new frmMain().Show();
You don't need to execute the Main() method, because all it does is work that your new project already does:
The [STAThread] sets the entry point thread (which becomes the main UI thread) to the STA apartment model. But since your new project is also (it seems) a Winforms program, you already have an entry point and a main UI thread that has been correctly configured. It's this thread in which the Click event for button1 is raised, and so you are executing in that thread when the button1_Click() method is called.
Likewise, the calls to set the visual styles and text rendering. You don't need to call these again, because your new project called them when it started.
Finally, the call to Application.Run(new frmMain()). This call has three effects: it creates an instance of frmMain() (which you can do yourself as I noted above), it then passes that instance to the Application.Run() method so that method can call the Show() method on the form (again, you can do that yourself), and then the Run() method sits in a loop dispatching window messages. You also don't need to do that because, again, you are already in a Winforms program, which has already called Application.Run(), and is already dispatching window messages (which is how the Click event got raised in the first place).
So, stop trying to invoke the Main() method, just make sure the form class you want to use is public so it's visible from projects that reference the assembly, and just create and show the frmMain object the way you would if it were declared in the same project.
I think it's because of the access modifier of the class program just change it to public.
also if you don't load a changeable dll (dynamic) why you don't just reference it to the project as you would normally do with other dll's and call the main from the program class (you still need program class to be public)
In Solution Explorer, in your project view right click on References --> Add New Reference --> Browse --> Find VTRSTCACodeMaintenance.dll(it should be in your \bin\debug folder) --> double click it --> click Ok.
That is basically.

Cannot Access Disposed Object

I have a form, which is the main form that the user will work from. When the user presses a button another form loads (this displays a list of customers etc.).
When I exit the customer form, and then click on the button again, I get the "cannot access disposed object" error message.
Any ideas? I'm a beginner at this.
custForm custForm = new custForm();
private void button5_Click(object sender, EventArgs e)
{
custForm.Show();
}
The problem is simple. You declare outside the click method the form variable. This is a class instance variable, meaning that it is visible in every method of the class in which is contained.
But when you close the custForm via its own button, this variable points to a disposed object, meaning that the data area pointed by the variable has been freed and it is available for reuse by other part of your program.
The runtime error says it all. You cannot access this area.
A possible workaround is to check the property IsDisposed and if it returns true recreate the form
custForm cf = new custForm();
private void button5_Click(object sender, EventArgs e)
{
if(cf == null || cf.IsDisposed == true)
cf = new custForm();
cf.Show();
}
You just cannot reuse an instance which was already disposed (see IDisposable). You have to create a new instance of the other form to be able to open it again.

Visual Studio 'find all references' fails for event handlers?

Here is some simple sample C# code in Visual Studio 2008:
public partial class Form1 : Form
{
private static System.Timers.Timer TestTimer;
public Form1()
{
InitializeComponent();
TestTimer = new System.Timers.Timer();
TestTimer.Elapsed += DoSomething;
}
private void DoSomething(Object source, EventArgs e)
{
}
}
If I right click on the DoSomething assigned as a handler, and select Go to definition, VS finds the body of DoSomething. So far so good.
If I Right Click on it and Find all references it finds nothing. (!?)
If I do either of these actions for the body of DoSomething itself, it finds only itself, not the assignment as an event handler.
Am I missing something obvious? A setting perhaps? In all other cases when you ask for all references that includes the definition and every other reference. I realize the assignment is thinking in terms of delegates, but this seems inconsistent. It would be very convenient to easily find when something was assigned as a handler.
Your event handler declaration is not quite up to snuff. The ElapsedEventHandler delegate has a different signature. Fix:
void DoSomething(object sender, System.Timers.ElapsedEventArgs e) {
// etc..
}
IntelliSense now will be able to find all references. Do favor using IntelliSense to get the event assignment correct. After you type +=, press the Tab key twice to let it automatically generate the code.

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