I'm developing an application in Xamarin for Android which needs to get a list of calendars. I've found an example how to do it but there is used CursorLoader which is mark as deprecated. I wasn't able to find a replacement of the function in Xamarin. Is there an another way how to get list of calendars?
Thanks.
AndroidCalendarModels _androidCalendarModel = new AndroidCalendarModels();
string[] calendarsProjection = {
CalendarContract.Calendars.InterfaceConsts.Id,
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName,
CalendarContract.Calendars.InterfaceConsts.AccountName
};
var calendarsUri = CalendarContract.Calendars.ContentUri;
var loader = new CursorLoader(Android.App.Application.Context, calendarsUri, calendarsProjection, null, null, null);
var cursor = (ICursor)loader.LoadInBackground();
while (cursor.MoveToNext())
{
int calId = cursor.GetInt(0);
string calName = cursor.GetString(1);
string calAccount = cursor.GetString(2);
_androidCalendarModel.Calendars.Add(new AndroidCalendarModel()
{
Id = calId,
AccountName = calAccount,
CalendarDisplayName = calName,
});
}
Related
I am following this article for Select Multiple Images From Gallery in Xamarin Forms.
I completed the feature in android part but the picture path contains only the picture name, extensions are missing when saving path.
To upload the image to the server I need the complete image name with extension. So how can I save the complete path of the selected images with the extension?
Following method capture the image path:
public String GetRealPathFromURI(Android.Net.Uri contentURI)
{
try
{
ICursor imageCursor = null;
string fullPathToImage = "";
imageCursor = ContentResolver.Query(contentURI, null, null, null, null);
imageCursor.MoveToFirst();
int idx = imageCursor.GetColumnIndex(MediaStore.Images.ImageColumns.Data);
if (idx != -1)
{
fullPathToImage = imageCursor.GetString(idx);
}
else
{
ICursor cursor = null;
var docID = DocumentsContract.GetDocumentId(contentURI);
var id = docID.Split(':')[1];
var whereSelect = MediaStore.Images.ImageColumns.Id + "=?";
var projections = new string[] { MediaStore.Images.ImageColumns.Data };
cursor = ContentResolver.Query(MediaStore.Images.Media.InternalContentUri, projections, whereSelect, new string[] { id }, null);
if (cursor.Count == 0)
{
cursor = ContentResolver.Query(MediaStore.Images.Media.ExternalContentUri, projections, whereSelect, new string[] { id }, null);
}
var colData = cursor.GetColumnIndexOrThrow(MediaStore.Images.ImageColumns.Data);
cursor.MoveToFirst();
fullPathToImage = cursor.GetString(colData);
}
return fullPathToImage;
}
catch (Exception ex)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "Unable to get path", ToastLength.Long).Show();
}
return null;
}
The extension(.png or .jpg) was missing not from the GetRealPathFromURI(), it happens in ImageHelpers.SaveFile(). So I save the filename to another variable from the path using Path.GetFileName() like below and pass the complete filename when call ImageHelpers.SaveFile().
var fileName = Path.GetFileName(picturepath);
I have the following command where I get my notification in ios, I want to get my key more I'm not getting it, what I tried was
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Messaging.SharedInstance.AppDidReceiveMessage(userInfo);
NSString[] keys = { new NSString("Event_type") };
NSObject[] values = { new NSString("Recieve_Notification") };
var parameters = NSDictionary<NSString, NSObject>.FromObjectsAndKeys(keys, values, keys.Length);
Firebase.Analytics.Analytics.LogEvent("CustomEvent", parameters);
System.Diagnostics.Debug.WriteLine(userInfo);
// var aps_d = userInfo["aps"] as NSDictionary;
//var alert_d = aps_d["alert"] as NSDictionary;
//var body = alert_d["keys"] as NSString;
}
System.Diagnostics.Debug.WriteLine
receive this
[0:] {
aps = {
alert = {
body = "teste";
title = "teste";
};
};
"gcm.message_id" = "0:1505400569099941%712ac0f8712a1234";
"gcm.n.e" = 1;
"google.c.a.c_id" = 5974019197827881234;
"google.c.a.c_l" = "teste";
"google.c.a.e" = 1;
"google.c.a.ts" = 1505400123;
"google.c.a.udt" = 0;
keys = 152113;
}
keys is a top level and last entry in the dictionary, so you can directly access it via userInfo["keys"], i.e:
var keys = userInfo["keys"] as NSString;
How do you set a new Contact with a yearless birthday with Xamarin iOS?
iOS Documentation states you can just leave the NSDateComponent.year field blank for a yearless birthday.
After trying this in Xamarin iOS, it bugs out the birthday field on the New Contact UI, making it unusable.
var store = new CNContactStore();
var contact = new CNMutableContact();
// construct birthday w/o year
var birthDate = new NSDateComponents();
birthDate.Month = 11;
birthDate.Day = 12;
contact.Birthday = birthDate;
// pop iOS Contact UI
var editor = CNContactViewController.FromNewContact (contact);
editor.ContactStore = store;
editor.AllowsActions = false;
editor.AllowsEditing = true;
navcontroller.PushViewController(editor,true);
You need to save the contact first, then the iOS Contact Editor can handle the year-less date correctly.
var store = new CNContactStore();
var contact = new CNMutableContact()
{
GivenName = "Stack",
FamilyName = "Overflow"
};
var birthDate = new NSDateComponents();
contact.Birthday = new NSDateComponents()
{
Month = 11,
Day = 12,
};
######
var saveRequest = new CNSaveRequest();
saveRequest.AddContact(contact, null);
NSError error;
store.ExecuteSaveRequest(saveRequest, out error);
######
var editor = CNContactViewController.FromNewContact(contact);
editor.ContactStore = store;
editor.AllowsActions = false;
editor.AllowsEditing = true;
PresentViewControllerAsync(editor, true);
Figured it out. You have to set the calendar in the NSDateComponents to Gregorian.
var store = new CNContactStore();
var contact = new CNMutableContact();
// construct birthday w/o year
var birthDate = new NSDateComponents();
birthDate.Calendar = new NSCalendar(NSCalendarType.Gregorian);
birthDate.Month = 11;
birthDate.Day = 12;
contact.Birthday = birthDate;
// pop iOS Contact UI
var editor = CNContactViewController.FromNewContact (contact);
editor.ContactStore = store;
editor.AllowsActions = false;
editor.AllowsEditing = true;
navcontroller.PushViewController(editor,true);
I recently have a very weird behaviour, so weird I'm starting to wonder if the culprit could be the unit framework I'm using (XUnit). I asked a question about it there: Can Expressmapper copy to destination? but this one is no longer about Expressmapper but about XUnit.
Do you know if in some way XUnit can intefere with the code?
Here's a the reason I'm asking:
I can run those 'together or separatly) in any order and I always get this crazy behaviour:
First test fails (Test_xxx)
Second test pass (Test_Map)
Both tests contain the very same code!!
[Fact]
[Trait("Test kind", "Integration")]
public void Test_xxx()
{
// Arrange
var mapper = new MappingServiceProvider();
mapper.Register<MapSource, MapDestination>();
var src = new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid(),
Parent = new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid()
}
};
src.Children = Enumerable.Range(0, 3).Select(i => new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid()
}).ToList();
var dst = new MapDestination();
// Act
mapper.Map(src, dst);
// Assert
var compare = new CompareLogic(new ComparisonConfig
{
IgnoreObjectTypes = true
});
var comparison = compare.Compare(src, dst);
Assert.Equal(new List<Difference>(), comparison.Differences);
}
[Fact]
[Trait("Test kind", "Integration")]
public void Test_Map()
{
// Arrange
var mapper = new MappingServiceProvider();
mapper.Register<MapSource, MapDestination>();
var src = new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid(),
Parent = new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid()
}
};
src.Children = Enumerable.Range(0, 3).Select(i => new MapSource
{
Id = Guid.NewGuid().GetHashCode(),
Guid = Guid.NewGuid()
}).ToList();
var dst = new MapDestination();
// Act
mapper.Map(src, dst);
// Assert
var compare = new CompareLogic(new ComparisonConfig
{
IgnoreObjectTypes = true
});
var comparison = compare.Compare(src, dst);
Assert.Equal(new List<Difference>(), comparison.Differences);
}
I had another method called Test_Map (with a different signature; aka overload).
I guess XUnit requires method name to be unique (something I intended to do).
I followed this example Changing schema name on runtime - Entity Framework where I can create a new EntityConnection from a MetaDataWorkspace that I then use to construct a DbContext with a different schema, but I get compiler warnings saying that RegisterItemCollection method is obsolete and to "Construct MetadataWorkspace using constructor that accepts metadata loading delegates."
How do I do that? Here is the code that is working but gives the 3 warnings for the RegsiterItemCollection calls. I'm surprised it works since warning says obsolete not just deprecated.
public static EntityConnection CreateEntityConnection(string schema, string connString, string model)
{
XmlReader[] conceptualReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".csdl")
)
};
XmlReader[] mappingReader = new XmlReader[]
{
XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".msl")
)
};
var storageReader = XmlReader.Create(
Assembly
.GetExecutingAssembly()
.GetManifestResourceStream(model + ".ssdl")
);
//XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/02/edm/ssdl"; // this would not work!!!
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl";
var storageXml = XElement.Load(storageReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet"))
{
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null)
{
schemaAttribute.SetValue(schema);
}
}
storageXml.CreateReader();
StoreItemCollection storageCollection =
new StoreItemCollection(
new XmlReader[] { storageXml.CreateReader() }
);
EdmItemCollection conceptualCollection = new EdmItemCollection(conceptualReader);
StorageMappingItemCollection mappingCollection =
new StorageMappingItemCollection(
conceptualCollection, storageCollection, mappingReader
);
//var workspace2 = new MetadataWorkspace(conceptualCollection, storageCollection, mappingCollection);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories
.GetFactory(connectionData.Provider)
.CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
I was able to get rid of the 3 warning messages. Basically it wants you to register the collections in the constructor of the MetadataWorkspace.
There are 3 different overloads for MetadataWorkspace, I chose to use the one which requires to to supply a path (array of strings) to the workspace metadata. To do this I saved readers to temp files and reloaded them.
This is working for me without any warnings.
public static EntityConnection CreateEntityConnection(string schema, string connString, string model) {
var conceptualReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".csdl"));
var mappingReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".msl"));
var storageReader = XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream(model + ".ssdl"));
XNamespace storageNS = "http://schemas.microsoft.com/ado/2009/11/edm/ssdl";
var storageXml = XElement.Load(storageReader);
var conceptualXml = XElement.Load(conceptualReader);
var mappingXml = XElement.Load(mappingReader);
foreach (var entitySet in storageXml.Descendants(storageNS + "EntitySet")) {
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null) {
schemaAttribute.SetValue(schema);
}
}
storageXml.Save("temp.ssdl");
conceptualXml.Save("temp.csdl");
mappingXml.Save("temp.msl");
MetadataWorkspace workspace = new MetadataWorkspace(new List<String>(){
#"temp.csdl",
#"temp.ssdl",
#"temp.msl"
}
, new List<Assembly>());
var connectionData = new EntityConnectionStringBuilder(connString);
var connection = DbProviderFactories.GetFactory(connectionData.Provider).CreateConnection();
connection.ConnectionString = connectionData.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
Not wanting to create temp files which slows the process down, I found an alternate answer to this is fairly simple. I replaced these lines of code -
//var workspace2 = new MetadataWorkspace(conceptualCollection, storageCollection, mappingCollection);
var workspace = new MetadataWorkspace();
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
with this one line of code -
var workspace = new MetadataWorkspace(() => conceptualCollection, () => storageCollection, () => mappingCollection);
and that works fine.