I'm creating a Helper to find out if the user is using my app for the first time (not only), that's why I'm using Xamarin.Forms.Aplication.Current.Properties. When the user logs out, the app will remove all keys, include that. But this is not happening and I don't know what.
My code:
public static class FirstUseAppHelper
{
public static string FIRST_USE = "FirstUse";
public static void Initialize()
{
if (Application.Current.Properties.ContainsKey(FIRST_USE))
{
Application.Current.Properties[FIRST_USE] = false;
}
else
{
Application.Current.Properties[FIRST_USE] = true;
}
}
public static bool CheckFirstUseApp()
{
if (!Application.Current.Properties.ContainsKey(FIRST_USE))
throw new Exception("Key not found.");
else
return Application.Current.Properties[FIRST_USE].Equals(true);
}
}
When the app starts (App.Xaml.cs) is called the method:
protected override async void OnInitialized()
{
InitializeComponent();
FirstUseAppHelper.Initialize();
...
}
Logout method (This is not working):
LogOutCommand = new DelegateCommand(() =>
{
var keys = Application.Current.Properties.Keys.ToList();
foreach (var k in keys)
Application.Current.Properties[k] = null;
Application.Current.SavePropertiesAsync();
}
I understand that the code is correct, but for some reason the keys are not being erased. Has anyone had this problem or has a better solution?
This is because the automatic backup of the latest versions of Android.
You need to add android:allowBackup="false" and android:fullBackupContent="false" to the tag in AndroidManifest.xml
if you don't want to back up your data or if you want to include or exclude some features.
Related
im currently expanding my knowledge a little, and wanted to Create a little game for myself.
The Structure is as Following:
Programm.cs creates an instance of Gamecontroller. This Gamecontroller is the lowest level i want to Access. It will create instaces of the Views, and from classes like config.
I want to implement an debug Console with Command Input. These Commands should always start at the Gamecontroller level, and should be able to interact with kinda everything i could do with C# code.
So i want to access the Objects, Member and methods withing Gamecontroller, or Within any nested object.
Currently i cant get to the Properties of an Child, because _member returns an "Type" which gets parsed to RuntimeProperty instead of the Class
Example on Parsing:
"objPlayer.name" > "GameController.objPlayer.name"
"objConfig.someSetting = 10" > "GameController.objConfig.someSetting=10"
"objConfig.functionCall()" > "GameController.objConfig.functionCall()"
"objConfig.objPlayer.setName("someName")" > "GameController.objConfig.objPlayer.setName("someName")"
"objPlayer.name" > "GameController.objPlayer.name"
this is what i got so far:
private void parseComamnd(string Command)
{
var actions = Command.Split('.');
var start = this.GetType();
var last = actions[actions.Length - 1];
foreach (var action in actions)
{
if (action.Contains("(") && action.Contains(")"))
{
_exec(start, action);
}
else
{
start = _member(start, action);
}
}
}
private Type _member(Type pHandle, string pStrMember)
{
return pHandle.GetProperty(pStrMember).GetType();
}
private void _exec(Type pHandle, string pStrFunction)
{
var Regex = new Regex(#"\(|,|\)");
var FunctionParams = Regex.Split(pStrFunction);
var FunctionName = FunctionParams[0];
FunctionParams[0] = "";
FunctionParams = FunctionParams.Where(val => val != "").ToArray();
pHandle.GetMethod(FunctionName).Invoke(FunctionName, FunctionParams);
}
If I understood right, you want to match some string commands with actions you want to perform. In this case you could use Dictionary as a storage for string-delgate couples to match your string commands to actions you want to perform. As an advantage of this approach, you can change matched couples during program runtime as you wish
class SomeClass
{
delegate void OperationDelegate(string value);
IDictionary<string, OperationDelegate> Operations = new Dictionary<string, OperationDelegate>();
public SomeClass()
{
Operations.Add("objPlayer.name", SetName);
Operations.Add("objConfig.someSetting", SetSetting);
}
public void HandleNewValue(string command, string value)
{
try
{
if (Operations.ContainsKey(command))
Operations[command](value);
}
catch (Exception e)
{
Logger.Error(e);
}
}
private void SetName(string value)
{
// Some logic there
}
private void SetSetting(string value)
{
// Some logic there
}
}
I'm using the TicTacToss code as a basis for a turn based game on android in Unity, using this : https://github.com/playgameservices/play-games-plugin-for-unity
Everything is working great, but there's no functionality exposed to return a list of games the current user is engaged in, active and completed. I need this for the main UI, so I can show the user what games they are playing, against whom etc. Without, this API seems pretty lacking.
Has anyone been able to get this going? Seems to me that the functionality might be there, as there is a function called GetAllTurnbasedMatches(), but my C# isn't strong enough to understand how it works. (see in https://github.com/playgameservices/play-games-plugin-for-unity/blob/master/source/PluginDev/Assets/GooglePlayGames/Platforms/Native/PInvoke/TurnBasedManager.cs)
(more info # https://github.com/playgameservices/play-games-plugin-for-unity/issues/414)
I managed to get this working back adding the following to NativeTurnBasedMultiplayerClient.cs:
public void GetAllTBMatches(Action<TurnBasedMatch, TurnBasedMatch.MatchTurnStatus> callback)
{
mTurnBasedManager.GetAllTurnbasedMatches(allMatches =>
{
foreach (var match in allMatches.MatchesMyTurn())
{
var converted = match.AsTurnBasedMatch(mNativeClient.GetUserId());
Logger.d("MY turn : Passing converted match to user callback:" + converted);
callback(converted, TurnBasedMatch.MatchTurnStatus.MyTurn);
}
foreach (var match in allMatches.MatchesTheirTurn())
{
var converted = match.AsTurnBasedMatch(mNativeClient.GetUserId());
Logger.d("Their Turn : Passing converted match to user callback:" + converted);
callback(converted, TurnBasedMatch.MatchTurnStatus.TheirTurn);
}
foreach (var match in allMatches.MatchesCompleted())
{
var converted = match.AsTurnBasedMatch(mNativeClient.GetUserId());
Logger.d("Completed : Passing converted match to user callback:" + converted);
callback(converted, TurnBasedMatch.MatchTurnStatus.Complete);
}
callback(null, TurnBasedMatch.MatchTurnStatus.Unknown);
});
}
public void GetAllTBInvitations(Action<Invitation> callback)
{
mTurnBasedManager.GetAllTurnbasedMatches(allMatches =>
{
foreach (var invitation in allMatches.Invitations())
{
var converted = invitation.AsInvitation();
Logger.d("Passing converted invitation to user callback:" + converted);
callback(converted);
}
callback(null);
});
}
You also need to edit the following in TurnBasedManager.cs
internal class TurnBasedMatchesResponse : BaseReferenceHolder {
internal TurnBasedMatchesResponse(IntPtr selfPointer) : base(selfPointer) {
}
protected override void CallDispose(HandleRef selfPointer) {
C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_Dispose(SelfPtr());
}
internal CommonErrorStatus.MultiplayerStatus Status() {
return C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetStatus(SelfPtr());
}
internal IEnumerable<MultiplayerInvitation> Invitations()
{
return PInvokeUtilities.ToEnumerable(
C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetInvitations_Length(SelfPtr()),
index => new MultiplayerInvitation(C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetInvitations_GetElement(SelfPtr(), index)));
}
internal IEnumerable<NativeTurnBasedMatch> MatchesMyTurn()
{
return PInvokeUtilities.ToEnumerable(
C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetMyTurnMatches_Length(SelfPtr()),
index => new NativeTurnBasedMatch(C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetMyTurnMatches_GetElement(SelfPtr(), index)));
}
internal IEnumerable<NativeTurnBasedMatch> MatchesTheirTurn()
{
return PInvokeUtilities.ToEnumerable(
C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetTheirTurnMatches_Length(SelfPtr()),
index => new NativeTurnBasedMatch(C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetTheirTurnMatches_GetElement(SelfPtr(), index)));
}
internal IEnumerable<NativeTurnBasedMatch> MatchesCompleted()
{
return PInvokeUtilities.ToEnumerable(
C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetCompletedMatches_Length(SelfPtr()),
index => new NativeTurnBasedMatch(C.TurnBasedMultiplayerManager_TurnBasedMatchesResponse_GetCompletedMatches_GetElement(SelfPtr(), index)));
}
internal static TurnBasedMatchesResponse FromPointer(IntPtr pointer)
{
if (PInvokeUtilities.IsNull(pointer)) {
return null;
}
return new TurnBasedMatchesResponse(pointer);
}
}
I was able to populate a comboBox via StreamReader on the MainForm. I find now that I will need that same information in several different comboBox's on different dialog's. This works accept that I can't seem to be able to get at the comboBox "cbTask". Error states "The name 'cbTask' does not exist in the current context". The code
public static void TaskPopulate()
{
try
{
StreamReader task = new StreamReader(dataFolder + TasksFile);
string tasks = task.ReadLine();
while (tasks != null)
{
cbTask.Items.Add(tasks);
tasks = task.ReadLine();
}
}
catch
{
}
}
dataFolder is the path and TasksFile is the file name. Works good if I leave it on the MainForm.
Can anyone point me in the right direction?? Thanks for viewing in advance!! I appreciate it. Have a Great Day!!
EDIT: After reading over this a few times it looks like my question is not clear. I'm trying to add information from the StreamReader to multiple comboBoxes on multiple child dialogs.
My first answer provided an Enterprise-style solution, so here is another approach if you wanted a simpler and less expansive way to handle your challenge.
public static class MyTaskComboBoxPopulater()
{
public static void LoadTasksToCombobox(ComboBox comboBox)
{
try
{
StreamReader task = new StreamReader(dataFolder + TasksFile);
string tasks = task.ReadLine();
while (tasks != null)
{
comboBox.Items.Add(tasks);
tasks = task.ReadLine();
}
}
catch
{
}
}
}
public Form MainForm()
{
public static void TaskPopulate()
{
MyTaskComboBoxPopulater.LoadTasksToCombobox(cbTask);
}
}
Move it to a new Service, and depend on the Service reference for whichever Form you need.
Sample code:
public class MyService()
{
public IEnumerable<string> LoadTasks()
{
var taskList = new List<string>();
try
{
StreamReader task = new StreamReader(dataFolder + TasksFile);
string tasks = task.ReadLine();
while (tasks != null)
{
taskList.Add(tasks);
tasks = task.ReadLine();
}
}
catch
{
}
return taskList;
}
}
public Form MainForm()
{
private MyService _myService = new MyService();
public static void TaskPopulate()
{
foreach(var task in _myService.LoadTasks())
{
cbTask.Items.Add(task);
}
}
}
Do you have that method in the main window or in a seperate class? If it is in a seperate class, that might explain why "cbTask" Cannot be found.
Also, try using something similar to this string variable = otherForm.TextBox1.Text;
Currently I'm implementing a Screen indicating wheater a module is not existing or still in development.
The Back Button has the following code:
regionNavigationService.Journal.GoBack();
This is working as expected. But the user is not coming from the Home Screen. So I need to access the View Name from the last Entry in Navigation Journal.
Example: User is coming from Settings Screen => The text should display "Back to Settings Screen"
Assuming the view name you are looking for is when you do new Uri("Main", UriKind.Relative) that you would want the word Main as the view name.
The forward and backward stacks in the RegionNavigationJournal are private. You could use reflection to get access to it.
var journal = regionNavigationService.Journal as RegionNavigationJournal;
if (journal != null)
{
var stack =
(Stack<IRegionNavigationJournalEntry>)
typeof (RegionNavigationJournal).GetField("backStack",
BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(journal);
var name = stack.Peek().Uri.OriginalString;
}
Or a better way is to implement your own IRegionNavigationJournal that is a wrapper around it. This is using Unity to constructor inject the default RegionNavigationJournal if using MEF you might need to put the ImportingConstructorAttribute on it.
public class RegionNavigationJournalWrapper : IRegionNavigationJournal
{
private readonly IRegionNavigationJournal _regionNavigationJournal;
private readonly Stack<Uri> _backStack = new Stack<Uri>();
// Constructor inject prism default RegionNavigationJournal to wrap
public RegionNavigationJournalWrapper(RegionNavigationJournal regionNavigationJournal)
{
_regionNavigationJournal = regionNavigationJournal;
}
public string PreviousViewName
{
get
{
if (_backStack.Count > 0)
{
return _backStack.Peek().OriginalString;
}
return String.Empty;
}
}
public bool CanGoBack
{
get { return _regionNavigationJournal.CanGoBack; }
}
public bool CanGoForward
{
get { return _regionNavigationJournal.CanGoForward; }
}
public void Clear()
{
_backStack.Clear();
_regionNavigationJournal.Clear();
}
public IRegionNavigationJournalEntry CurrentEntry
{
get { return _regionNavigationJournal.CurrentEntry; }
}
public void GoBack()
{
// Save current entry
var currentEntry = CurrentEntry;
// try and go back
_regionNavigationJournal.GoBack();
// if currententry isn't equal to previous entry then we moved back
if (CurrentEntry != currentEntry)
{
_backStack.Pop();
}
}
public void GoForward()
{
// Save current entry
var currentEntry = CurrentEntry;
// try and go forward
_regionNavigationJournal.GoForward();
// if currententry isn't equal to previous entry then we moved forward
if (currentEntry != null && CurrentEntry != currentEntry)
{
_backStack.Push(currentEntry.Uri);
}
}
public INavigateAsync NavigationTarget
{
get { return _regionNavigationJournal.NavigationTarget; }
set { _regionNavigationJournal.NavigationTarget = value; }
}
public void RecordNavigation(IRegionNavigationJournalEntry entry)
{
var currentEntry = CurrentEntry;
_regionNavigationJournal.RecordNavigation(entry);
// if currententry isn't equal to previous entry then we moved forward
if (currentEntry != null && CurrentEntry == entry)
{
_backStack.Push(currentEntry.Uri);
}
}
}
If using unity in your Prism Bootstrapper you will need to replace the default registration of the IRegionNavigationJournal
protected override void ConfigureContainer()
{
this.RegisterTypeIfMissing(typeof(IRegionNavigationJournal), typeof(RegionNavigationJournalWrapper), false);
base.ConfigureContainer();
}
If using MEF you will need to put the ExportAttribute on top of the RegionNavigationJournalWrapper
[Export(typeof(IRegionNavigationJournal))]
You can see http://msdn.microsoft.com/en-us/library/gg430866%28v=pandp.40%29.aspx for more information on replacing their default implementation with your own. Once you have the wrapper you will still need to cast it as RegionNavigationJournalWrapper to get access to the PreviousViewName so still not perfect or create an interface that RegionNavigationJournalWrapper also implements to cast to that to get you access to the PreviousViewName
I have a very subtle bug that I'm having trouble identifying.
Background:
We have 2 sites running off the same application on the same web server.
SiteA -- accessed by www.SiteA.com
SiteB -- accessed by www.SiteB.com
When the request first comes in, the siteId is identified based on the Host and stored in the Session as follows:
protected void Application_BeginRequest(object sender, EventArgs e)
{
string host = Request.Url.Host;
int siteId = new SiteManager().GetSiteByUrl(host).SiteId;
if (SessionUser.Instance().SiteId != siteId)
{
SessionUser.Instance().SiteId = siteId;
}
}
This ID used later in determining what data to retreive and to determine what style to present:
// this happens during an initialization phase
_siteConfiguration = _siteManager.GetSiteById(SessionUser.Instance().SiteId);
// then later:
private void SetPageTheme()
{
string theme = null;
switch (_siteConfiguration.SiteId)
{
case ConfigurationHelper.SITE.A:
theme = "SiteATheme";
break;
case ConfigurationHelper.SITE.B:
theme = "SiteBTheme";
break;
}
Page.Theme = theme;
}
The problem:
the problem I'm facing is if you load both sites at almost exactly the same time, i.e. within milliseconds, sometimes SiteA will load with SiteB's theme and vice versa. This doesn't happen very often but it has come to the attention of the client so it's now a problem.. Something is happening somewhere within those few milliseconds in the difference between SiteA loading and SiteB loading, and I don't know how to identify what that is.
The question:
Does anyone have any ideas what could be going wrong here? Something is getting confused somewhere. Is it IIS mixing up the requests? Is it the Session mixing up the site it's supposed to return the SiteId for?
If any more info is needed, I'll supply it.
Update:
For reference, this is the definition of SessionUser (basically, create a static instance of an object to get the SiteId value from the Session):
public class SessionUser
{
private static SessionUser _instance;
public int SiteId { get; set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
public static SessionUser Instance()
{
if (null == _instance)
{
_instance = new SessionUser();
if (null != HttpContext.Current.Session)
{
if (null == HttpContext.Current.Session["User"])
{
if (HttpContext.Current.Request.QueryString["sid"] != null)
{
int nSiteId = int.Parse(HttpContext.Current.Request.QueryString["sid"]);
_instance.SiteId = nSiteId;
HttpContext.Current.Session["User"] = _instance;
}
}
else
{
_instance = (SessionUser) HttpContext.Current.Session["User"];
}
}
}
return _instance;
}
}
Without knowing what the 'SessionUser' class looks like, I can only speculate.
I will assume that SessionUser.Instance() returns a 'static' instance (or member rather).
Now, these will be shared across the entire application. So it makes sense that this cannot be shared between 2 sites.
I suggest you rather use HttpContext to store the setting at BeginRequest.
The code will then look like the following:
class SessionUser
{
public static SessionUser Instance()
{
var ctx = HttpContext.Current;
var su = ctx["SessionUser"] as SessionUser;
if (su == null)
{
ctx["SessionUser"] = su = new SessionUser();
}
return su;
}
}
I guess you could put the code that stores the current Site ID inside a lock block, but this may hamper performance. It makes more sense to use something not shared by both sites, as leppie says.
For the lock example:
if (SessionUser.Instance().SiteId != siteId)
{
lock(somePrivateStaticObject)
{
if (SessionUser.Instance().SiteId != siteId)
{
SessionUser.Instance().SiteId = siteId;
}
}
}