How to call Guide.BeginShowMessageBox - c#

I have a problem calling Guide.BeginShowMessageBox
Here is my code:
public object FuelTypeIndex { get; private set; }
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
var messageCommands = new Dictionary<string, Action>()
{
{ "Diesel", () => {FuelTypeIndex = 0;}},
{ "Petrol", () => {FuelTypeIndex = 1;}},
{ "Other", () => {FuelTypeIndex = 2;}},
};
var result = Guide.BeginShowMessageBox("Title", "Message", messageCommands.Keys, 0, MessageBoxIcon.Warning, null, null);
result.AsyncWaitHandle.WaitOne();
int? choice = Guide.EndShowMessageBox(result);
if (choice.HasValue)
messageCommands.ElementAt(choice.Value).Value.Invoke();
}
I get the following exception:
An exception of type 'System.ArgumentException' occurred in
Microsoft.Xna.Framework.GamerServices.ni.dll but was not handled in
user code
Additional information: The argument is invalid. It must contain
between 1 and 2 strings. The strings cannot be null or empty, and must
be less than 256 characters long.
By debugging I located the problem to messageCommands.Keys, because if I call the function with a static array it works just fine.
So what am I doing wrong?

The problem is the number of requested buttons in the call to Guide.BeginShowMessageBox. According to the documentation the maximum number of buttons is two on Windows Phone.

Related

Parallel.Invoke and Index was outside the bounds of the array [duplicate]

This question already has answers here:
List.Add() thread safety
(9 answers)
Closed last year.
I am sporadically seeing the following error,
System.IndexOutOfRangeException: Index was outside the bounds of the
array. at System.Collections.Generic.List`1.Add(T item)
I have a console application which connects to multiple data sources and generate report in excel format.
In order to speedup the process, I am using Parallel.Invoke and it saved approx 40% of time.
The code structure is as follows,
public static void Execute(List<Members> activeRecords)
{
var resultList = new List<Recon>();
var lookupList = DataManager.GetLookUpData();
Parallel.Invoke(
() =>
{
GenerateReportA(activeRecords, lookupList, resultList);
},
() =>
{
GenerateReportB(activeRecords, lookupList, resultList);
},
() =>
{
GenerateReportC(activeRecords, lookupList, resultList);
},
() =>
{
GenerateReportD(activeRecords, lookupList, resultList);
},
And each GenerateReport method has similar structure but, generates different reports based on the need. There are totally 32 reports.
private static void GenerateReportA(List<Members> activeData, List<Recon> resultList)
{
var message = string.Empty;
var reportName = $"{area} {Name}";
var reportDataList = null;
try
{
//logic which compares generates report data
}
catch (Exception ex)
{
message = $"Error: {ex.Message}";
}
AddToResult(reportName, reportDataList, message, resultList);
}
The issue is happening in AddToResult method at resultList.Add(recon);
private static void AddToResult(string reportName, IList data, string message, List<Recon> resultList)
{
var recon = new Recon
{
ReportName = reportName,
ExcelData = ExcelManager.GetExcelData(reportName, message, data)
};
resultList.Add(recon);
}
Need suggestion / guidance on how I can avoid this error but still using parallel.invoke. Any suggestion will be greatly appreciated.
The fundamental issue is that List<T>.Add is not thread safe. By trying to add to the same array in parallel, you are most likely causing an internal collision, potentially during resizing operations and it is leading to failed indexing.
The proper solution is to lock before adding:
private static object _locker = new object();
private static void AddToResult(string reportName, IList data, string message, List<Recon> resultList)
{
var recon = new Recon
{
ReportName = reportName,
ExcelData = ExcelManager.GetExcelData(reportName, message, data)
};
lock(_locker)
{
resultList.Add(recon);
}
}
If you change something in threads, make sure that no one can do that at the same time. In your case it easy, just add lock on list.
private static void AddToResult(string reportName, IList data, string message, List<Recon> resultList)
{
var recon = new Recon
{
ReportName = reportName,
ExcelData = ExcelManager.GetExcelData(reportName, message, data)
};
lock (resultList)
{
resultList.Add(recon);
}
}
Also ensure that your code do not change data list.

ScriptBuffer throws NullReferenceException when called from an Event as part of a loop - SSIS Script Component [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I have an SSIS package which calls a Data Flow Task as part of a loop which iterates different end-point addresses (out of scope).
The Data Flow Task has a source Script Component responsible for calling a REST API and creating a row for each result.
There are 3 output buffers;
1. actual data row
2. error row
3. monitoring
The monitoring buffer used for telemetry and is populated through an event (EventHander) that is fired every time the API makes a request.
During the first iteration of the ForEach int the Control Flow loop, everything runs as expected, all the buffers produce the correct rows.
However, during the next iterations, the monitoring buffer which is populated within the event throws;
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.HandleUserException(Exception e)
at Microsoft.SqlServer.Dts.Pipeline.ScriptComponentHost.PrimeOutput(Int32 outputs, Int32[] outputIDs, PipelineBuffer[] buffers)
at Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostPrimeOutput(IDTSManagedComponentWrapper100 wrapper, Int32 outputs, Int32[] outputIDs, IDTSBuffer100[] buffers, IntPtr ppBufferWirePacket)
I don't understand why the MonitoringBuffer is not initialised in the proceeding iterations.
The exception occurs while calling MonitoringBuffer.AddRow();.
Here's the whole Script Component simplified for readability:
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
private string ClientCode { get { return Variables.ErplyClientCode; } }
private string Username { get { return Variables.ErplyUsername; } }
private string Password { get { return Variables.ErplyPassword; } }
private bool IsTest { get { return Variables.IsTest; } }
private int ErplyRecordsPerPage { get { return Variables.ErplyRecordsPerPage; } }
private string ErplyDebugOutputPath { get { return Variables.ErplyDebugOutputPath; } }
private DateTime ChangeSince { get { return Variables.ChangeSince; } }
private int records { get; set; }
private int errors { get; set; }
private string rawFolder { get; set; }
public override void PreExecute()
{
base.PreExecute();
}
public override void PostExecute()
{
base.PostExecute();
}
public override void CreateNewOutputRows()
{
ErplyAPI.OnPreRequestEvent += new EventHandler<EAPIEvent>(ErplyAPI_OnPreRequestEvent);
var staff = ErplyAPI.getStaff(ClientCode, Username, Password, ChangeSince, ErplyRecordsPerPage, IsTest);
foreach (var p in staff.List)
{
try
{
if (!p.IsError)
{
EmployeeBuffer.AddRow();
EmployeeBuffer.employeeID = p.employeeID;
}
else
{
ErrorBuffer.AddRow();
ErrorBuffer.employeeID = p.employeeID;
ErrorBuffer.Error = p.Error.Message.Trim() + "\n" + p.Error.StackTrace;
errors++;
}
records++;
}
catch (Exception ex)
{
this.ComponentMetaData.FireWarning(0, "Script", ex.Message + "\n" + ex.StackTrace, string.Empty, 0);
}
}
EmployeeBuffer.SetEndOfRowset();
ErrorBuffer.SetEndOfRowset();
}
private void ErplyAPI_OnPreRequestEvent(object sender, EAPIEvent e)
{
var request = string.Empty;
var sessionKey = string.Empty;
bool fireAgain = true;
if (e == null)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
return;
}
if (e.eAPI == null)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("EAPIEvent.eAPI is NULL in ErplyAPI_OnPreRequestEvent. Amonit did not log the Erply request."), string.Empty, 0);
return;
}
try
{
if (e.Parameters != null && e.Parameters.ContainsKey("request"))
request = e.Parameters["request"].ToString();
if (request != "verifyUser" && e.Parameters != null && e.Parameters.ContainsKey("sessionKey"))
sessionKey = e.Parameters["sessionKey"].ToString();
}
catch (Exception ex)
{
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", string.Format("Error occurred assigning variables from EAPIEvent parameters in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace), string.Empty, 0);
}
try
{
MonitoringBuffer.AddRow(); // Exception occurs here
MonitoringBuffer.Request = ResizeString(request, 255);
MonitoringBuffer.SessionKey = ResizeString(sessionKey, 128);
}
catch (Exception ex)
{
var message = string.Format("Error occurred outputting Erply request in ErplyAPI_OnPreRequestEvent. {0} {1}", ex.Message, ex.StackTrace);
MonitoringBuffer.ErrorMessage = ResizeString(message, 8000);
ComponentMetaData.FireWarning(0, "SC_ERPLY_API", message, string.Empty, 0);
}
finally
{
MonitoringBuffer.EndOfRowset();
}
}
}
I sorted the problem out.
The exception was being raised when the variable dispenser was being accessed from the Event. For some reason the GetValueWithContext(ScriptComponent.EvaluatorContext) is being dropped during the second call. Why this happens is beyond me.
The solution is simple, assign the variables from the variables dispenser to a local property or variable in the OnPreExecute function.
It's also good practice to not call the variable dispenser in the CreateNewOutputRows as it cause variable locking.
I ran into this issue too, but my solution was a little different -- moving the variable assignments into PreExecute() didn't help.
Instead, what I'd done is that I wanted to parse three different files, and read each of them with a Script Component. Their columns were kinda similar, so I created one Data Flow task, made sure it worked, then copied it and modified each copy to reflect the differences in the files. Running each individual Data Flow task was successful, but when I tried to run two of them, one after the other in a loop, I got a NullReferenceException from HostPrimeOutput() after calling the OutputBuffer.AddRow() method in my Script Component.
It turns out that when I copied each Data Flow task, the Script Components all kept the same namespace, and I guess it doesn't like that. So, I created brand new Script Components, set up all the output columns again (ugh!), copied the body of the script over, and it's happy.

Windows Phone - How to handle navigation errors

How should I handle navigation errors if they occur in the OnNavigatedTo method. For example, a query string parameter is not passed or throws an exception while parsing to an integer.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string itemIdParam;
if (NavigationContext.QueryString.TryGetValue("itemId", out itemIdParam))
{
int itemId = int.Parse(NavigationContext.QueryString["itemId"]);
_item = App.MainViewModel.Items.Where(i => i.ItemId == itemId).First();
DataContext = _item;
}
}
Should I catch them and display a MessageBox or let them
Try like this:
if( this.NavigationContext.QueryString.ContainsKey("itemId"))
{
string s_itemid = this.NavigationContext.QueryString["itemId"];
int i_itemid;
bool result = Int32.TryParse(s_itemid, out i_itemid);
if(result)
//parsing success
else
//parsing error
}
else
//parameter doesn't exist
More information about TryParse: LINK
Another thing you can do to reduce the error is to define your navigation uri.
For example in Details.xaml page you can create a static method called GetUri() with parameters of wanted type.
public static Uri GetUri(int itemId){
return new Uri(string.Format("/Details.xaml?itemId={0}", itemId), UriKind.Relative);
}
When you want to navigate to Details page just write:
NavigationService.Navigate(Details.GetUri(2));

data type to use for an exception thrown by a validator?

I need to capture any exceptions thrown by the validator but I cannot figure out how to due it. Here is the code I have tried:
internal static class XMLValidator
{
public static void Validate(XElement elem)
{
string xsdMarkup;
using(var file = new StreamReader(Constants.Xsd))
{
xsdMarkup = file.ReadToEnd();
}
XmlSchemaSet schema = new XmlSchemaSet();
bool valid = true;
schema.Add(XmlSchema.Read(XElement.Parse(xsdMarkup).CreateReader(), (o, e) => { }));
new XDocument(elem).Validate(schema, (o, e) => { valid = false; exception = e; });
if (valid == false)
{
throw exception;
}
valid = true;
}
}
I get a "the name exception does not exist in current context" error. I'm pretty sure that the problem is that I have not given exception a data type. However I have no idea what type to use.
I tried adding var before the exception but then it's not recogonized inside of the if statement and of course var cannot be declared outside of a method
I then tried declaring exemption globally as a string and setting to e like this:
exception = e.ToString();
but then I can't throw it inside of the if statement.
How would I go about doing this?
The delegate you're using creates an XmlSchemaValidationException:
XmlSchemaValidationException exception = null;
new XDocument(elem).Validate(schema, (o, e) => { valid = false; exception = e.Exception; });
if (valid == false)
{
throw exception;
}
Well, in this particular case you probably want to create your own type of Exception to throw.
public class InvalidDataException : Exception
{ }
(There are times where it's appropriate to do something within the definition of the class, but in most cases you really don't need anything.)
Then you can do something like this:
throw new InvalidDataException("Error message goes here");
Or, you can find some existing type of exception to throw that is created by the standard library or what have you.

How to invoke a delegate with a null parameter?

I get a null exception if I try to pass a null parameter to a delegate during an invoke. Here's what the code looks like:
public void RequestPhoto()
{
WCF.Service.BeginGetUserPhoto(Contact.UserID,
new AsyncCallback(RequestPhotoCB), null);
}
public void RequestPhotoCB(IAsyncResult result)
{
var photo = WCF.Service.EndGetUserPhoto(result);
UpdatePhoto(photo);
}
public delegate void UpdatePhotoDelegate(Binary photo);
public void UpdatePhoto(Binary photo)
{
if (InvokeRequired)
{
var d = new UpdatePhotoDelegate(UpdatePhoto);
Invoke(d, new object[] { photo });
}
else
{
var ms = new MemoryStream(photo.ToArray());
var bmp = new Bitmap(ms);
pbPhoto.BackgroundImage = bmp;
}
}
The problem is with the line:
Invoke(d, new object[] { photo });
If the variable "photo" is null. What is the correct way to pass a null parameter during an invoke?
Thanks!
Just for the benefit of others, you can pass null arguments to delegates (if the type allows it? Clarification needed here). In your case, IAsyncResult will allow it.
As for the debugging, the exception occurs on Invoke because you are debugging on a given Thread A, the exception occurs on Thread B. You can breakpoint multiple threads. Breakpoint the Thread B code and you will see the exception closer to or on the source.
Notice though that your debugger will jump around if multiple threads are running code at the same time. Debugging in multiple threads is always at least a little tricky, but satisfying when you solve the problems.
You could also further improve your answer code to check the null before it checks the InvokeRequired, as this is thread-independent to your logic (your code checks it just prior to use, after Invoking). This will save pushing the Invoke onto the message pump (assuming WinForms).
OK I figured it out. The problem was NOT with passing the null parameter to the delegate like I thought. The problem was with the delegate executing it was causing a null exception on the line:
var ms = new MemoryStream(photo.ToArray());
I didn't realize the problem was there because it was crashing on the Invoke line.
So I changed the UpdatePhoto method as follows:
public void UpdatePhoto(Binary photo)
{
if (InvokeRequired)
{
var d = new UpdatePhotoDelegate(UpdatePhoto);
Invoke(d, new object[] { photo});
}
else
{
if (photo != null)
{
var ms = new MemoryStream(photo.ToArray());
var bmp = new Bitmap(ms);
pbPhoto.BackgroundImage = bmp;
}
}
}
And all is well!

Categories

Resources