RectForMapRect MonoTouch.UIKit.UIKitThreadAccessException - c#

I have this issue only in MonoTouch 5.4. DrawMapRect is multithreaded, but I need to use RectForMapRect here. Can I do it without InvokeOnMainThread?
Error:
MonoTouch.UIKit.UIKitThreadAccessException: UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.
at MonoTouch.UIKit.UIApplication.EnsureUIThread () [0x00019] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:49
at MonoTouch.MapKit.MKOverlayView.RectForMapRect (MKMapRect mapRect) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/MapKit/MKOverlayView.g.cs:146
at MapTest.MyMKOverlayView.DrawMapRect (MKMapRect mapRect, Single zoomScale, MonoTouch.CoreGraphics.CGContext context) [0x00009] in /Users/kirill/Desktop/MapTest/MapTest/MapTestViewController.cs:38
Source code here:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.MapKit;
namespace MapTest
{
public class MyMKMapView : MKMapView
{
public MyMKMapView(RectangleF frame) : base(frame)
{
GetViewForOverlay = GetViewForOverlayImp;
}
private MKOverlayView GetViewForOverlayImp(MKMapView mapView, NSObject overlay)
{
return new MyMKOverlayView();
}
public void AddNewOverlay()
{
AddOverlay(new MyMKOverlay());
}
}
public class MyMKOverlayView : MKOverlayView
{
public MyMKOverlayView() : base()
{
}
public override void DrawMapRect(MKMapRect mapRect, float zoomScale, MonoTouch.CoreGraphics.CGContext context)
{
base.DrawMapRect(mapRect, zoomScale, context);
RectForMapRect(new MKMapRect());
}
}
public class MyMKOverlay : MKOverlay
{
public override MKMapRect BoundingMapRect
{
get
{
return new MKMapRect(10 , 10 , 10 , 10);
}
}
public MyMKOverlay() : base()
{
}
}
public partial class MapTestViewController : UIViewController
{
private MyMKMapView _map;
public MapTestViewController() : base ("MapTestViewController", null)
{
_map = new MyMKMapView(View.Bounds);
View.AddSubview(_map);
}
public override void DidReceiveMemoryWarning()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
}
public override void ViewDidUnload()
{
base.ViewDidUnload();
// Clear any references to subviews of the main view in order to
// allow the Garbage Collector to collect them sooner.
//
// e.g. myOutlet.Dispose (); myOutlet = null;
ReleaseDesignerOutlets();
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
_map.AddNewOverlay();
}
public override bool ShouldAutorotateToInterfaceOrientation(UIInterfaceOrientation toInterfaceOrientation)
{
// Return true for supported orientations
return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
}
}
}
Error in line RectForMapRect(new MKMapRect()).

This check is a new feature of MonoTouch 5.4. By default the UI thread check is only enabled on DEBUG builds. You can, at build-time, manually:
disable it (on DEBUG) using --disable-thread-check; or
enable it (on Release) using --force-thread-check;
You can also turn it on/off at runtime using CheckForIllegalCrossThreadCalls.
It's possible that the check is not required, Apple documentation on thread safety is not very clear (unlike MSDN). If you find such case (or simply are not sure) then please fill a bug report.

Related

C# How to replace an Event by a Delegate?

Mac OS, VS Community, C#, Cocoa application.
The following code generates a run time error.
using AppKit;
using CoreGraphics;
using Foundation;
using System;
namespace NSTextFieldValidation
{
public partial class ViewController : NSViewController
{
public ViewController(IntPtr handle) : base(handle) { }
public override void ViewDidLoad()
{
base.ViewDidLoad();
var fm = new NSNumberFormatter { Maximum = 999, Minimum = 0 };
NSTextField Tbx1 = new NSTextField(new CGRect(10, 50, 100, 30));
View.AddSubview(Tbx1);
Tbx1.Formatter = fm;
Tbx1.Delegate = new MyTextFieldDelegate();
Tbx1.DidFailToValidatePartialString += TbxDidFailToValidatePartialString;
}
private void TbxDidFailToValidatePartialString(object sender, NSControlTextErrorEventArgs e)
{
Console.WriteLine("DidFailToValidatePartialString activated");
}
}
public class MyTextFieldDelegate : NSTextFieldDelegate
{
override public void EditingEnded(NSNotification notification)
{
Console.WriteLine("EditingEnded");
}
}
}
Here's the exception:
System.InvalidOperationException
Event registration is overwriting existing delegate. Either just use
events or your own delegate: NSTextFieldValidation.MyTextFieldDelegate
AppKit.NSTextField+_NSTextFieldDelegate
I understand that it is not correct to use event and delegate at the same time. I only ask which method I need to override in my delegate to deal with "DidFailToValidatePartialString", because I did not find it (perhaps I did not look well).
In the Delegate class, the DidFailToValidatePartialString method is not declared like others (i.e EditingEnded). We need to add an Export attribute:
[Export("control:didFailToValidatePartialString:errorDescription:")]
I would like the Xamarin documentation to explain this.

NUnit result are different in debug and release

I can't get rid of this problem. It's very strage, when I try to run my NUnit test in Debug mode, I get the expected result but when I just run it normally, the result is Wrong.
What i'm trying to do is detect Binding errors. Here is a sample
[TestFixture, RequiresSTA]
public class BindingTests
{
[Test]
public void T1_BindingErrorsExpected()
{
string error = null;
using (var listener = new ObservableTraceListener())
{
listener.TraceCatched += s => error = s;
TextBlock myText = new TextBlock();
UserControl control = new UserControl();
Binding myBinding = new Binding("BadBinding");
myBinding.Source = control;
myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
}
Assert.IsNotNull(error);
}
}
And the ObservableTraceListener
public sealed class ObservableTraceListener : DefaultTraceListener
{
private readonly StringBuilder _Builder = new StringBuilder();
public ObservableTraceListener()
{
PresentationTraceListener.Add(SourceLevels.Error, this);
}
public new void Dispose()
{
Flush();
Close();
PresentationTraceListener.Remove(this);
base.Dispose();
}
public override void Write(string message)
{
_Builder.Append(message);
}
public override void WriteLine(string message)
{
Write(message);
if (TraceCatched != null)
TraceCatched(_Builder.ToString());
_Builder.Clear();
}
public event Action<string> TraceCatched;
}
public static class PresentationTraceListener
{
public static void Add(SourceLevels level, TraceListener trace)
{
PresentationTraceSources.DataBindingSource.Listeners.Add(trace);
PresentationTraceSources.DataBindingSource.Switch.Level = level;
PresentationTraceSources.ResourceDictionarySource.Listeners.Add(trace);
PresentationTraceSources.ResourceDictionarySource.Switch.Level = level;
}
public static void Remove(TraceListener trace)
{
PresentationTraceSources.DataBindingSource.Listeners.Remove(trace);
PresentationTraceSources.ResourceDictionarySource.Listeners.Remove(trace);
}
}
Result in debug -> Fail (What I expect)
Result in Run-> Success (Not what expected)
Thanks MatthewMartin but I found the solution looking at https://github.com/bblanchon/WpfBindingErrors
The probem was my ObservableTraceListener.
I needed to add a static constructor calling PresentationTraceSources.Refresh() to get it works correctly. As said in MSDN doc, it Refreshes trace sources, by forcing the app.config file to be re-read. So, some initialization was just done when I started the test in "debug" mode, which probably caused the app.config file to be read.
MSDN doc -> PresentationTraceSources.Refresh() http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.refresh%28v=vs.100%29.aspx
Here is my final ObservableTraceListener and the PresentationTraceListener is the same as the one in the question
public sealed class ObservableTraceListener : TraceListener
{
private readonly StringBuilder _Builder = new StringBuilder();
static ObservableTraceListener()
{
PresentationTraceSources.Refresh();
}
public ObservableTraceListener()
{
PresentationTraceListener.Add(SourceLevels.Error, this);
}
public new void Dispose()
{
Flush();
Close();
PresentationTraceListener.Remove(this);
base.Dispose();
}
public override void Write(string message)
{
_Builder.Append(message);
}
public override void WriteLine(string message)
{
_Builder.Append(message);
if (TraceCatched != null)
TraceCatched(_Builder.ToString());
_Builder.Clear();
}
public event Action<string> TraceCatched;
}
Posting an answer because a comment would be too small to hold what I want to say...
There is no reference to PresentationTraceListener on the internet-- how it treats the TraceListener is important because AFAIK the PresentationTraceListener is what calls the Write/WriteLine methods of the TraceListener (possibly indirectly via TraceSource)
This code below compiles in a brand new project. If I Write(x), I get null, if I writeLine(x), I get a value. Generally when you write a custom TraceListener, you redirect all the overloads to a single method so that they all behave the same (Write and WriteLine should be identical except WriteLine tacks a newline onto the message for the caller.)
Another observation is that System.Diagnostics trace is a quirky logging library whose main advantage is that it is always available even when there is some barrier to using 3rd party libraries. System.Diagnostics trace really wants you to register a TraceSwitch, TraceListener in your app.config or web.config and use that to enable & disable trace. It also requires the the TRACE flag be registered (in the same way the DEBUG flag gets registered, in the project properities-- by default TRACE is defined for DEBUG and RELEASE)
[TestFixture, RequiresSTA]
public class BindingTests
{
[Test]
public void T1_BindingErrorsExpected()
{
string error = null;
using (var listener = new ObservableTraceListener())
{
listener.TraceCatched += s => error = s;
//TextBlock myText = new TextBlock();
//UserControl control = new UserControl();
//Binding myBinding = new Binding("BadBinding");
//myBinding.Source = control;
//myText.SetBinding(TextBlock.BackgroundProperty, myBinding);
PresentationTraceSources.DataBindingSource.TraceEvent(TraceEventType.Error,0, "Hello World!");
}
Assert.IsNotNull(error);
Console.WriteLine(error);
}
}
public sealed class ObservableTraceListener : TraceListener
{
private readonly StringBuilder _Builder = new StringBuilder();
public ObservableTraceListener()
{
//PresentationTraceListener.Add(SourceLevels.Error, this);
}
protected override void Dispose(bool disposing)
{
Flush();
Close();
//PresentationTraceListener.Remove(this);
}
public override void Write(string message)
{
_Builder.Append(message);
}
public override void WriteLine(string message)
{
Write(message);
if (TraceCatched != null)
TraceCatched(_Builder.ToString());
_Builder.Clear();
}
public event Action<string> TraceCatched;
}

How to subscribe to an event with certain arguments c#?

I have an enumeration prior.
Each of my scripts has a property priority of prior type. (Every script has its own class)
I have a data provider, which can send events every frame.
I want a script to subscribe only to an event which has arguments with priority equal to the script's one.
For example, a script with moderate priority should receive only events with moderate parameter of event arguments
prior has too many members to create a special event argument class for each.
Unfortunately:
a)I know only how to subscribe to a certain event type.
b)I can't make a generic class for event arguments, because elements of enum are not types
How can I do it?
The project currently looks this way:
public class TDefault:MonoBehaviour,IDefault
{
public enum prior
{
none,
...,
terminal
};
prior priority;
public virtual void apply()//For override by scripts
{
}
void Start()
{
//There should be adding a method which calls apply() when event_manager
//sends Event with a certain priority
}
public TDefault ()
{
if(essential==null)
essential=new TEssential();
}
}
public class TApplyEventParam : EventArgs
{
public TDefault.prior priority;
public TApplyEventParam(TDefault.prior _priority)
{
priority=_priority;
}
}
public class event_manager : TDefault
{
//This has fixed type
event EventHandler<TApplyEventParam> handler=new EventHandler<TApplyEventParam>();
void Update ()
{
foreach (prior p in (prior[]) Enum.GetValues(typeof(prior)))
{
handler(this,new TApplyEventParam(p));
}
}
}
The problem you're dealing with, if I understood it correctly, is that you would like to have your event subscription conditionally called depending on the event payload (the priority value inside the TApplyEventParam). That is something that you cannot do which results in you having to filter out the unwanted events inside your event handler like proposed by #Henk-Holterman
Another approach could be to skip the usage of events and maintain your own list of subscribers inside the data provider.
Based on the terminology used by you in your question (not the code example) you could do something like this:
using System;
using System.Collections.Generic;
namespace Example
{
public enum Prior
{
None,
Moderate,
Terminal
};
public abstract class ScriptBase
{
public abstract Prior Prior { get; }
public abstract void Apply();
public void Start(DataProvider dataProvider)
{
dataProvider.Subscribe(Prior, Apply);
}
public void Stop(DataProvider dataProvider)
{
dataProvider.Unsubscribe(Prior, Apply);
}
}
public class ScriptHandlingModerateEvents : ScriptBase
{
public override Prior Prior
{
get { return Example.Prior.Moderate; }
}
public override void Apply()
{
Console.WriteLine("Handling moderate event by " + GetType().Name);
}
}
public class ScriptHandlingTerminalEvents : ScriptBase
{
public override Prior Prior
{
get { return Example.Prior.Terminal; }
}
public override void Apply()
{
Console.WriteLine("Handling terminal event by " + GetType().Name);
}
}
public class DataProvider
{
private readonly Dictionary<Prior, List<Action>> _subscribersByPrior;
public DataProvider()
{
_subscribersByPrior = new Dictionary<Prior, List<Action>>();
foreach (Prior prior in (Prior[])Enum.GetValues(typeof(Prior)))
{
_subscribersByPrior.Add(prior, new List<Action>());
}
}
public void Subscribe(Prior prior, Action action)
{
_subscribersByPrior[prior].Add(action);
}
public void Unsubscribe(Prior prior, Action action)
{
_subscribersByPrior[prior].Remove(action);
}
public void DoSomethingThatTriggersPriorEvents(int someValue)
{
Prior prior = someValue % 2 == 0 ? Prior.Moderate : Prior.Terminal;
foreach (var subscriber in _subscribersByPrior[prior])
{
subscriber();
}
}
}
public static class Program
{
public static void Main()
{
DataProvider dataProvider = new DataProvider();
var scriptHandlingModerateEvents = new ScriptHandlingModerateEvents();
scriptHandlingModerateEvents.Start(dataProvider);
var scriptHandlingTerminalEvents = new ScriptHandlingTerminalEvents();
scriptHandlingTerminalEvents.Start(dataProvider);
for (int i = 0; i < 10; i++)
{
dataProvider.DoSomethingThatTriggersPriorEvents(i);
}
scriptHandlingTerminalEvents.Stop(dataProvider);
scriptHandlingModerateEvents.Stop(dataProvider);
Console.WriteLine();
}
}
}
this way the DataProvider is not aware of scripts, but if that is not an issue, you could maintain a list of ScriptBase instances and check the Prior property inside the
DoSomethingThatTriggersPriorEvents like this:
public class DataProvider2
{
private readonly List<ScriptBase> _scripts = new List<ScriptBase>();
public void Subscribe(ScriptBase script)
{
_scripts.Add(script);
}
public void Unsubscribe(ScriptBase script)
{
_scripts.Remove(script);
}
public void DoSomethingThatTriggersPriorEvents(int someValue)
{
Prior prior = someValue % 2 == 0 ? Prior.Moderate : Prior.Terminal;
foreach (var script in _scripts)
{
if (script.Prior == prior)
{
script.Apply();
}
}
}
}

Service variables reset when calling activity closed in android

I am having this issue for a couple of days now, i did a lot of searching in the Internet, but did not find something that works in my case.
I have a service :
namespace Demo_Service_Name
{
public static class MyGlobals
{
...
public static int DurSelection;
}
class Service_Connection : Java.Lang.Object, IServiceConnection
{...}
public class Demo_Service : Service
{
public void Setup_Service(int DSel)
{
MyGlobals.DurSelection = DSel;
}
public int Get_Duration_Selection()
{
return MyGlobals.DurSelection;
}
...
}
}
and my Activity goes like this:
using Demo_Service_Name
namespace Demo_Activity
{
public class Activity1 : Activity
{
protected override void OnCreate(Bundle bundle)
{
....
ThisService = new Intent(this, typeof(Demo_Service));
if (isMyServiceRunning())
{
demoServiceConnection = new Neural_Service_Connection(this);
isBound = BindService(ThisService, demoServiceConnection, Bind.none);
int servVar = binder.GetDemoService().Get_Duration_Selection();
}
}
protected void OnStartMyService()
{
....
StartService(ThisService);
isBound = BindService(ThisService, demoServiceConnection, Bind.none);
binder.GetDemoService().Setup_Service(A_Certain_Number);
}
}
}
So what I want to do is to start the service from the activity, bind to it, pass a value, close the activity, reopen the activity and read the variable back into the activity if the service is running.
All works like it should, except that when i close the activity, the value in the service variable is reset.
What do you think am I missing?
PS. I am sure the Service.OnDestroy has not been called

How to get DirectoryModuleCatalog to work?

I am using Prism 4 and MEF for a WPF project. I have some DLL that needs to be loaded from a directory. These DLL implements IModule through IGame and are properly formed (or at least I think so) :
[Module(ModuleName = "SnakeModule")]
class SnakeModule : IGame
{
public void Initialize()
{
Console.WriteLine("test");
}
public void StartGame()
{
throw new NotImplementedException();
}
}
Currently, the main project is compiling but the module doesn't get initialized. I have trouble understanding how to setup my bootstrapper and the documentation isn't helping much since it doesn't have full example with a DirectoryModuleCatalog. The modularity quickstart isn't compiling either. Here is my bootstrapper :
class BootStrap : MefBootstrapper
{
protected override DependencyObject CreateShell()
{
return ServiceLocator.Current.GetInstance<Shell>();
}
protected override void InitializeShell()
{
Application.Current.MainWindow = (Window)this.Shell;
Application.Current.MainWindow.Show();
}
protected override void ConfigureAggregateCatalog()
{
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(BootStrap).Assembly));
}
protected override IModuleCatalog CreateModuleCatalog()
{
DirectoryModuleCatalog catalog = new DirectoryModuleCatalog() { ModulePath = #"..\..\..\GameTestLib\bin\Debug" };
return catalog;
}
protected override void ConfigureContainer()
{
base.ConfigureContainer();
}
}
Paths for the DLLs are correct. To sum up, my question is : How should I setup my bootstrapper ?
First, and since you're using Prism, I suggest that you go with ModuleExport, as follows :
[ModuleExport("SnakeModule", typeof(IGame))]
But your problems actually comes from the fact you didn't set your class as a public one, therefore preventing the discovery of your module. So you need to change your code to this :
[ModuleExport("SnakeModule", typeof(IGame))]
public class SnakeModule : IGame
{
public void Initialize()
{
Console.WriteLine("test");
}
public void StartGame()
{
throw new NotImplementedException();
}
}
And it should be fine !

Categories