I am trying to change the AudioTrack title every 3 seconds, but It seems I cannot change it or it could not be possible using below:
void timer_Tick(object sender, EventArgs e)
{
BackgroundAudioPlayer player = BackgroundAudioPlayer.Instance;
switch (player.PlayerState)
{
case PlayState.Playing:
if (recitation != null && recitation.Count > 0)
{
if (++ayaRecitationCounter == recitation.Count)
{
ayaRecitationCounter = 0;
recitationTimer.Stop();
}
else
{
player.Track.Title = ayaRecitationCounter.ToString(); //Exception occurs here recitationTimer.Interval=TimeSpan.FromSeconds(recitation[ayaRecitationCounter].AyaDuration);
lsbReadingChapter.SelectedIndex = ayaRecitationCounter;
lsbReadingChapter.ScrollIntoView(lsbReadingChapter.SelectedIndex);
}
}
break;
}
}
The application is crushing and providing me below message:
Operation is not valid due to the current state of the object.
at Microsoft.Phone.BackgroundAudio.AudioTrack.set_Title(String value)
How can I change the title?
Thanks!
If you want to Edit AudioTrack once it's created you will have to use BeginEdit as MSDN says:
Once the track has been created using one of the AudioTrack constructors, then the BeginEdit() and EndEdit() methods must be used to update the object.
As I've checked - I was able to change Title (for example) while playing by this code:
AudioTrack track = BackgroundAudioPlayer.Instance.Track;
track.BeginEdit();
track.Title = "New Title";
track.EndEdit();
(accessing by a reference is needed here)
Of course it will be suitable to put some try-catch blocks in your code.
Pease also be aware that your Timer will work only when your App is in Foreground.
Related
We have built a huge winforms project, already in progress for multiple years.
Sometimes, our users get an exception which looks like this one.
The resolution of this problem seems to be:
don't acces UI components from a background thread
.
But since our project is a very big project with a lot of different threads, we don't succeed in finding all these.
Is there a way to check (with some tool or debugging option) which components are called from a background thread?
To clarify:
I created a sample winforms project with a single Form, containing two Button
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Text = "Clicked!";
}
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
button2.BackColor = Color.Red; //this does not throw an exception
//button2.Text = "Clicked"; //this throws an exception when uncommented
});
}
}
The background color of button2 is set to red when the button is clicked. This happens in a background thread (which is considered bad behavior). However, it doesn't (immediately) throw an exception. I would like a way to detect this as 'bad behavior'. Preferably by scanning my code, but if it's only possible by debugging, (so pausing as soon as a UI component is accessed from a background thread) it's also fine.
I've got 2 recommendations to use together, the first is a Visual Studio Plugin called DebugSingleThread.
You can freeze all the threads and work on one at a time (obviously the non-main-UI threads) and see each threads access to controls. Tedious I know but not so bad with the second method.
The second method is to get the steps in order to reproduce the problem. If you know the steps to reproduce it, it will be easier to see whats causing it. To do this I made this User Action Log project on Github.
It will record every action a user makes, you can read about it here on SO: User Activity Logging, Telemetry (and Variables in Global Exception Handlers).
I'd recommend you also log the Thread ID, then when you have been able to reproduce the problem, go to the end of the log and work out the exact steps. Its not as painful as it seems and its great for getting application telemetry.
You might be able to customise this project, eg trap a DataSource_Completed event or add a dummy DataSource property that sets the real Grids DataSource property and raises an INotifyPropertyChanged event - and if its a non-main thread ID then Debugger.Break();.
My gut feeling is you're changing a control's (eg a grid) data source in a background thread (for that non-freeze feel) and thats causing a problem with synchronisation. This is what happened to the other DevExpress customer who experienced this. Its discussed here in a different thread to the one you referenced.
Is your app set to ignore cross threading intentionally?
Cross-thread operations should be blowing up all the time in winforms. It checks for them like crazy in just about every method. for a starting point check out https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs.
Somewhere in your app, somebody might have put this line of code:
Control.CheckForIllegalCrossThreadCalls = False;
Comment that out and run the app, then follow the exceptions.
(Usually you can fix the problem by wrapping the update in an invoke, e.g., in a worker thread if you see textbox1.text=SomeString; change it to `textbox.invoke(()=>{textbox1.text=SomeString;});.
You may also have to add checking for InvokeRequired, use BeginInvoke to avoid deadlocks, and return values from invoke, those are all separate topics.
this is assuming even a moderate refactor is out of the question which for even a medium sized enterprise app is almost always the case.
Note: it's not possible to guarantee successful discovery of this case thru static analysis (that is, without running the app). unless you can solve the halting problem ... https://cs.stackexchange.com/questions/63403/is-the-halting-problem-decidable-for-pure-programs-on-an-ideal-computer etc...
I did this to search for that specific situation but of course, need to adjust it to your needs, but the purpose of this is to give you at least a possibility.
I called this method SearchForThreads but since it's just an example, you can call it whatever you want.
The main idea here is perhaps adding this Method call to a base class and call it on the constructor, makes it somewhat more flexible.
Then use reflection to invoke this method on all classes deriving from this base, and throw an exception or something if it finds this situation in any class.
There's one pre req, that is the usage of Framework 4.5.
This version of the framework added the CompilerServices attribute that gives us details about the Method's caller.
The documentation for this is here
With it we can open up the source file and dig into it.
What i did was just search for the situation you specified in your question, using rudimentary text search.
But it can give you an insight about how to do this on your solution, since i know very little about your solution, i can only work with the code you put on your post.
public static void SearchForThreads(
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
var startKey = "this.Controls.Add(";
var endKey = ")";
List<string> components = new List<string>();
var designerPath = sourceFilePath.Replace(".cs", ".Designer.cs");
if (File.Exists(designerPath))
{
var designerText = File.ReadAllText(designerPath);
var initSearchPos = designerText.IndexOf(startKey) + startKey.Length;
do
{
var endSearchPos = designerText.IndexOf(endKey, initSearchPos);
var componentName = designerText.Substring(initSearchPos, (endSearchPos - initSearchPos));
componentName = componentName.Replace("this.", "");
if (!components.Contains(componentName))
components.Add(componentName);
} while ((initSearchPos = designerText.IndexOf(startKey, initSearchPos) + startKey.Length) > startKey.Length);
}
if (components.Any())
{
var classText = File.ReadAllText(sourceFilePath);
var ThreadPos = classText.IndexOf("Task.Run");
if (ThreadPos > -1)
{
do
{
var endThreadPos = classText.IndexOf("}", ThreadPos);
if (endThreadPos > -1)
{
foreach (var component in components)
{
var search = classText.IndexOf(component, ThreadPos);
if (search > -1 && search < endThreadPos)
{
Console.WriteLine($"Found a call to UI thread component at pos: {search}");
}
}
}
}
while ((ThreadPos = classText.IndexOf("Task.Run", ++ThreadPos)) < classText.Length && ThreadPos > 0);
}
}
}
I hope it helps you out.
You can get the Line number if you split the text so you can output it, but i didn't want to go through the trouble, since i don't know what would work for you.
string[] lines = classText.Replace("\r","").Split('\n');
Try that:
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new ThreadExceptionEventHandler(exception handler);
// Set the unhandled exception mode to force all Windows Forms errors to go through the handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += // add the handler here
// Runs the application.
Application.Run(new ......);
}
Then you can log the message and the call stack and that should give you enough information to fix the issue.
I recommend you update your GUI to handle this situation automatically for your convenience. You instead use a set of inherited controls.
The general principle here is to override the property Set methods in a way to make them Thread Safe. So, in each overridden property, instead of a straight update of the base control, there's a check to see if an invoke is required (meaning we're on a separate thread the the GUI). Then, the Invoke call updates the property on the GUI thread, instead of the secondary thread.
So, if the inherited controls are used, the form code that is trying to update GUI elements from a secondary thread can be left as is.
Here is the textbox and button ones. You would add more of them as needed and add other properties as needed. Rather than putting code on individual forms.
You don't need to go into the designer, you can instead do a find/replace on the designer files only. For example, in ALL designer.cs files, you would replace System.Windows.Forms.TextBox with ThreadSafeControls.TextBoxBackgroundThread and System.Windows.Forms.Button with ThreadSafeControls.ButtonBackgroundThread.
Other controls can be created with the same principle, based on which control types & properties are being updated from the background thread.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadSafeControls
{
class TextBoxBackgroundThread : System.Windows.Forms.TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
class ButtonBackgroundThread : System.Windows.Forms.Button
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
}
Good day fellow helpers, i have following problem:
(running MS Visual Community Edition 2015)
private void button4_Click(object sender, EventArgs e) // Senden
{
serialPort2.WriteLine("SR,00,002\r\n");
textBox1.Text = "gesendet";
textBox3.Text = "";
try
{
System.IO.StreamReader file = new System.IO.StreamReader("C:\\blub.txt");
String line = file.ReadToEnd();
string Hallo = line; \\in the beginning there is "0" in the file
file.Close();
decimal counter = Convert.ToDecimal(Hallo); \\just for testing
counter++;
string b = serialPort2.ReadLine();
string[] b1 = Regex.Split(b, "SR,00,002,"); \\cuts off unwanted input from device
decimal b2 = decimal.Parse(b1[1]); \\number like -3000
System.IO.StreamWriter test = new System.IO.StreamWriter("C:\\blub.txt");
test.WriteLine(counter);
test.Close();
textBox7.Text = "Das ist counter:" + counter;
}
catch (TimeoutException)
{
textBox3.Text = "Timeout";
throw;
}
}
Now, the Serialport is a device that returns a lengthmeasurment. As it is a bit weird, or just the way its build it start with a negitve number (between -5000 and -3370). Now as i want to get measurement on the screen that is realistic i want to set the value to 0 and calculate the difference.
Means: I start the programm - press send - get a value (say -3000) - press send again (after pushing the seonsor in) and get the value that its been pushed in > 0 by adding the difference to 0.
I only learned to store values externally when i had a C course a year back like i did within my programm. Is there a way to store the value from the first measurement in the programm so i can use it on the next send/try?
The counter was just for testing and I would exchange it for the "decimal b2"
I hope there is an easy fix for that, not really a pro with C# yet but i'm eager to learn. I thank the willing helpers in advance, MfG, Chris
OK, I will simplify this in order to show concept so it will not have all the code you are actually using.
So, what you want is to click on button, get some values and store them for next click.
Value is stored in variable. If you have variable in function that is handler for click event, as soon as function completes execution, value will be destroyed.
So, what you need is to create variable in outer scope (class level). Your function is already in class of the form so let's get to code:
class Form1
{
string BetweenClickStorage;
private void button4_Click(object sender, EventArgs e)
{
//Load data here
BetweenClickStorage = LoadedData;
}
}
After this, when you click again on the button, value will still be in BetweenClickStorage. It will be also available to all other buttons click handlers and other code in that form.
If I'm understanding your question correctly, the answer is simply to declare a variable outside the try/catch:
//declare variable //
var measurement;
// TRY #1 //
try
{
//assign value to the variable here
}
catch
{
}
// TRY #2 //
try
{
// reference variable here
}
catch
{
}
I'm having the same problem posed here:
http://social.msdn.microsoft.com/Forums/wpapps/en-us/af8615e7-8e90-4069-aa4d-3c4a84a6a3d0/windows-phone-8-fast-app-resume-with-deeplinks?forum=wpdevelop
I'm no C# or WP expert, so please bear with me.
I have secondary tiles which link to "/MainPage.xaml?id=XX".
I have fast app resume enabled. (ActivationPolicy="Resume" in the app manifest)
I only have one page in my app: MainPage.xaml.
Problem: When I resume the app using a secondary tile ("/MainPage.xaml?id=XX"), I get a brief view of the previous instance (that would have resumed) and then the MainPage initializes again, creating a new instance. In effect, the app is loading from scratch after giving me a peek of what was previously open.
That is obviously undesired behavior. I want to use the existing instance to perform my task.
Attempt 1:
Use e.Cancel = true; to cancel the navigation to the MainPage.xaml:
(using the App.xaml.cs code from the official Fast App Resume sample to identify how the app was launched)
...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
// This block will run if the previous navigation was a relaunch
wasRelaunched = false;
if (e.Uri.ToString().Contains("="))
{
// This block will run if the launch Uri contains "=" (ex: "id=XX") which
// was specified when the secondary tile was created in MainPage.xaml.cs
sessionType = SessionType.DeepLink;
e.Cancel = true; // <======================== Here
// The app was relaunched via a Deep Link.
// The page stack will be cleared.
}
}
...
Problem: In doing so, my OnNavigatedTo event handlers never fire, so my query string is never parsed.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
String navId;
if (e.NavigationMode != System.Windows.Navigation.NavigationMode.Back)
{
if (NavigationContext.QueryString.TryGetValue("id", out navId))
{
MessageBox.Show(navId.ToString()); // Not reached
}
}
...
Attempt 2:
Use e.Cancel = true; to cancel the navigation to the MainPage.xaml, AND pass the Uri to a method in MainPage:
// App.xaml.cs
...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
// This block will run if the previous navigation was a relaunch
wasRelaunched = false;
if (e.Uri.ToString().Contains("="))
{
// This block will run if the launch Uri contains "=" (ex: "id=XX") which
// was specified when the secondary tile was created in MainPage.xaml.cs
sessionType = SessionType.DeepLink;
e.Cancel = true;
MainPage.GoToDeepLink(e.Uri); // <======================== Here
// The app was relaunched via a Deep Link.
// The page stack will be cleared.
}
}
...
// MainPage.xaml.cs
public static void GoToDeepLink(Uri uri) // <======================== Here
{
// Convert the uri into a list and navigate to it.
string path = uri.ToString();
string id = path.Substring(path.LastIndexOf('=') + 1);
MyList list = App.ViewModel.ListFromId(Convert.ToInt32(id));
pivotLists.SelectedItem = list;
}
Problem: I get an error that pivotLists is non-static and thus requires an object reference. I think that in order to get this to work I'd need to create a new instance of MainPage (MainPage newMainPage = new MainPage();) and call newMainPage.pivotLists.SelectedItem = list; -- BUT I don't know how to use newMainPage instead of the existing one/replace it... or if that's something I want/won't cause further problems/complications.
I don't know what the solution is to this problem, and I may be going in the completely wrong direction. Please keep all suggestions in simple terms with code examples if you can, I'm still learning.
Thanks for any help.
It seems that when you reopen your App from secondary tile, then it's reactivated and new instance of MainPage is created (even if there is one from previous run). If I understood you correctly, I've managed to do such a thing:
In app.xaml.cs:
I've added a variable which indicates if I should return to previous MainPage after Navigating from secondary tile - it needs to be static as I want to have access to it from MainPage
public static bool returnPage = false;
In RootFrame_Navigating I'm setting this variable to true in:
// ...
else if (e.NavigationMode == NavigationMode.New && wasRelaunched)
{
// This block will run if the previous navigation was a relaunch
wasRelaunched = false;
returnPage = true;
// ...
In ClearBackStackAfterReset - prevent from deleting the old Page, when returning:
// ...
if (e.NavigationMode != NavigationMode.New || returnPage)
return;
// ...
In MainPage.cs:
I've changed a little constructor, as I don't want to see a blink of a new Page:
public MainPage()
{
if (!App.returnPage)
InitializeComponent();
}
In MainPage I've also variable which is passed from secondary tile - it's also static, as I need only one instance of it:
private static string navId = "";
And the core of the trick - OnNavigatedTo:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (App.returnPage)
{
App.returnPage = false;
NavigationContext.QueryString.TryGetValue("id", out navId);
NavigationService.GoBack();
}
else if (e.NavigationMode != NavigationMode.Reset)
{
// normal navigation
}
}
It works like this:
when you launch normally your App, returnPage is false, everything goes normal
when you activate it from secondary tile few things happen:
1. first goes navigation to your previous page with NavigationMode.Reset - we are not interested in it, so I switched it off - nothing should happen
2. then program tries to create new instance of MainPage, but returnPage is true, and because of the if statement, InitializeComponent won't run. Just after this, in OnNavigatedTo, program saves passed querystring and Navigates Back to previous instance of MainPage - from previous run
3. at last we are navigating to right MainPage with NavigationMode.Back and we have our querystring saved in static variable.
You must be aware of two things: first - probably it can be little rebuild (I'm not sure if wasRelaunched is needed and so on) - you need to debug it and see of what you can get rid off. Second - you will probably need to test your App with Tombstone case.
Hope this helps.
I have an Internet radio app that uses BackgroundAudioPlayer.
I need a timer in the Audio Playback Agent that will update the track title of the currently playing track of the BAP that is pulled from the Internet radio station's API.
Adding a DispatcherTimer into the Audio Playback Agent gives me a cross-thread exception, and using:
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Code
});
Didn't work.
I need the code in here because if I put the update code in the app itself, when the user navigates away from the app the updates stop (much unlike Windows 8's behavior).
I can't use Scheduled Agents since they only run once every 30 minutes (IIRC).
Is this possible or can this not be done on Windows Phone?
Below is an excerpt from the MSDN documentation for Background Audio Player:
Sending messages between tasks:
There are times when you will want to communicate between the two processes of a background audio app. For example, you might want the background task to notify the foreground task when a new track starts playing, and then send the new song title to the foreground task to display on the screen. A simple communication mechanism raises events in both the foreground and background processes. The SendMessageToForeground and SendMessageToBackground methods each invoke events in the corresponding task. Data can be passed as an argument to the event handler in the receiving task. Pass data using a new class called ValueSet. This class is a dictionary that contains a string as a key and other value types as values. You can pass simple value types such as int, string, bool, and so on.
https://msdn.microsoft.com/en-US/library/windows/apps/xaml/dn642090
Hope this helps!
I found a question which could help you : How to run a timer on background in windows phone 8?
when you set a timer which is checking every x seconds if the "title" differs from last known title then you could send this info back to it.
This could be the Code for the Timer:
Declare these:
string _newValue = string.Empty;
string _currentValue = string.Empty;
AudioTrack _tempTrack = null;
and set this as Tick for the Timer
if (this.BackgroundAudioPlayer != null)
{
if (this.BackgroundAudioPlayer.Instance != null)
{
if (this.BackgroundAudioPlayer.Instance.Track != null)
{
this._newValue= yourAPI.GetTitleOfTrack();
try
{
/* First try to get the current Track as own Var */
this._tempTrack = this.BackgroundAudioPlayer.Instance.Track;
if (this._tempTrack != null)
{
/* Then Read the .Tag Value from it, save to _currentValue */
if (this._tempTrack.Tag != null)
{ this._currentValue = this._tempTrack.Tag.ToString(); }
else
{ this._currentValue = string.Empty; }
/* Compare */
if (this._currentValue != this._newValue)
{
/* Edit the Track Tag from your original BAP */
this.BackgroundAudioPlayer.Instance.Track.Tag = this._newValue;
}
}
}
catch(Exception ex)
{
/* if something Crashes you can save the exception error for protocol */
}
}
}
}
Remember: Change "yourAPI.GetTitleOfTrack()"-Function from this with real Function Call of your API.
Have you considered updating the information in the background audio player agent as below in the track tag.
string newTag = "whatever you need to show";
AudioTrack track = BackgroundAudioPlayer.Instance.Track;
track.BeginEdit();
track.Tag = newTag;
track.EndEdit();
and then reading that tag in the front end by your application when needed?
I'm currently developing a metro app in which the user can change current language at runtime and all the custom controls that are loaded must update their text regarding to the new language. Problem is that when I change the language using the following code, the app language changes but it will only update text when I restart my app because the pages and controls that are already rendered are cached.
LocalizationManager.UICulture = new System.Globalization.CultureInfo((string)((ComboBoxItem)e.AddedItems[0]).Tag);
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = ((ComboBoxItem)e.AddedItems[0]).Tag as String;
What should I do to force updating text of all custom controls at runtime without restarting my app?
Use this:
var NewLanguage = (string)((ComboBoxItem)e.AddedItems[0]).Tag;
Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = NewLanguage;
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForViewIndependentUse().Reset();
//Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Reset();
Windows.ApplicationModel.Resources.Core.ResourceManager.Current.DefaultContext.Reset();
and then reload your Page, using Navigate method:
if (Frame != null)
Frame.Navigate(typeof(MyPage));
In order to respond right away, you would need to reset the context of the resource manager.
For Windows 8.1:
var resourceContext = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView();
resourceContext.Reset();
You will still need to force your page to redraw itself and thus re-request the resources to get the changes to take place. For Windows 8, you can see https://timheuer.com/blog/archive/2013/03/26/howto-refresh-languages-winrt-xaml-windows-store.aspx
You can change the app's language at runtime with the help of this source code. I took help from this and manipulated my app's language settings page as follows:
In languageSettings.xaml.cs:
public partial class LanguageSettings : PhoneApplicationPage
{
public LanguageSettings()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (ChangeLanguageCombo.Items.Count == 0)
{ ChangeLanguageCombo.Items.Add(LocalizationManager.SupportedLanguages.En);
ChangeLanguageCombo.Items.Add(LocalizationManager.SupportedLanguages.Bn);
}
SelectChoice();
}
private void ButtonSaveLang_OnClick(object sender, RoutedEventArgs e)
{
//Store the Messagebox result in result variable
MessageBoxResult result = MessageBox.Show("App language will be changed. Do you want to continue?", "Apply Changes", MessageBoxButton.OKCancel);
//check if user clicked on ok
if (result == MessageBoxResult.OK)
{
var languageComboBox = ChangeLanguageCombo.SelectedItem;
LocalizationManager.ChangeAppLanguage(languageComboBox.ToString());
//Application.Current.Terminate(); I am commenting out because I don't neede to restart my app anymore.
}
else
{
SelectChoice();
}
}
private void SelectChoice()
{
//Select the saved language
string lang = LocalizationManager.GetCurrentAppLang();
if(lang == "bn-BD")
ChangeLanguageCombo.SelectedItem = ChangeLanguageCombo.Items[1];
else
{
ChangeLanguageCombo.SelectedItem = ChangeLanguageCombo.Items[0];
}
}
}
***Note: Before understanding what I did on LanguageSettings page's code behind, you must implement the codes from the link as stated earlier. And also it may be noted that I am working on windows phone 8