UWP - Saving Settings does not work all the time - xaml

I've got the following code just copied from here. I want to bind a double value to a xaml slider, get this value from the localsetting every time I navigate to the SettingsPage and everytime the slidervalue gets changed by the user I want it to be saved to localsettings. Here is my code so far:
SettingsPage.xaml.cpp:
Windows::Storage::ApplicationDataContainer^ localSettings = Windows::Storage::ApplicationData::Current->LocalSettings;
SettingsPage::SettingsPage()
{
InitializeComponent();
this->viewModel = ref new SettingsViewModel();
this->DataContext = this->viewModel;
}
void SettingsPage::QSlider_ValueChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs^ e)
{
Windows::Storage::ApplicationDataCompositeValue^ composite =ref new Windows::Storage::ApplicationDataCompositeValue();
bool a = composite->Insert(SETTINGS_TAG_SLIDER_Q, dynamic_cast<PropertyValue^>(PropertyValue::CreateDouble((double)sldQ->Value)));
auto values = localSettings->Values;
bool b = values->Insert(SETTINGS_TAG_SETTINGS_PAGE, composite);
}
SettingsPage.xaml:
<Slider x:Name="sldQ" Margin="15,5,15,0" Value="{Binding SliderQValue}" ValueChanged="Slider_ValueChanged" MaxWidth="300" HorizontalContentAlignment="Left" ></Slider>
SettingsViewModel.cpp:
double SettingsViewModel::SliderQValue::get()
{
Windows::Storage::ApplicationDataContainer^ localSettings = Windows::Storage::ApplicationData::Current->LocalSettings;
ApplicationDataCompositeValue^ composite = safe_cast<ApplicationDataCompositeValue^>(localSettings->Values->Lookup(SETTINGS_TAG_SETTINGS_PAGE));
if (composite != nullptr)
{
if (composite->HasKey(SETTINGS_TAG_SLIDER_Q)) {
double value = safe_cast<IPropertyValue^>(composite->Lookup(SETTINGS_TAG_SLIDER_Q))->GetDouble();
return value;
}
}
return 99;
}
My Problem is that this works exactly once! If I navigate from other pages to SettingsPage, I get slidervalue=99. Then I set it by dragging to e.g. 50. Then I navigat back to other page. From the other page I navigate again to SettingsPage and get slidervalue=50. But doing it once again I get 99 again. So it only works for 1 page navigation-cycle but it should work even if the app is rebooted. What is the problem in my code? Am I understanding something wrong?

I actually solved the problem with the help of this. In my code above I was initializing a new 'ApplicationDateCompositeValue' each time I wanted to write/read it. So with the new method it works like it was planned to do:
OnValueChanged:
Windows::Storage::ApplicationDataContainer^ localSettings = Windows::Storage::ApplicationData::Current->LocalSettings;
auto values = localSettings->Values;
values->Insert(TAG_SLIDER, dynamic_cast<PropertyValue^>(PropertyValue::CreateDouble((double)sldQuality->Value)));
Property::get():
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
auto values = localSettings->Values;
if (localSettings->Values->HasKey(TAG_SLIDER)) {
double value = safe_cast<double>(localSettings->Values->Lookup(TAG_SLIDER));
return value;
}
else
return default_value;

Related

XAML forms have second picker sorted based on selection in first picker

I have 2 dropdowns (pickers) on a XAML form. The first is an ObservabelCollection of Territories. The second is an ObservableCollection of type Tracks. When the form loads my ViewModel loads both collections and each collection is bound to a picker. I want to filter and display only those tracks that are associated with the selected territory in the second picker.
FYI-the second picker is disabled until a selection is made in the first. Actually I don't require that the second picker's data source be set as the form loads, unless the solution requires it. The selection in the first picker will be the key to filter the data for the second.
I have tried to handle the filtering in the Territory picker's SelectedIndexChanged event but my ObservableCollection 'tracks' is not exposed here.
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
Tracks _track = tracks.Where(X => X.Territory = territory);<<<==== Does not work
trackPicker.ItemsSource = _track.Track;<<<==== Does not work
trackPicker.IsEnabled = true;
}
I've also tried to not build the Tracks OC until after the Territory is selected like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
TrackViewModel vm = new TrackViewModel();
var _tracks = (Tracks)vm.Tracks; <<<<<==== This does not work
trackPicker.IsEnabled = true;
}
The ViewModel runs and the tracks are loaded via the API but when it returns here Tracks is empty.
I'm open to a reasonable solution (not 3rd party controls/packages) that will accomplish this task . Thanks
I figured it out by stumbling over the answer while researching another issue. I have been referencing my viewmodel in the {content].xaml page like this.
<ContentPage.BindingContext>
<vm:TrackViewModel />
</ContentPage.BindingContext>
When doing so the resources of that vm were not available in the code behind. But when I reference the VM in the page constructor Like this:
public partial class RequestmyTracks : ContentPage
{
TrackViewModel trackviewmodel = new TrackViewModel();
And then bind it here:
public RequestmyTracks()
{
InitializeComponent();
BindingContext = trackviewmodel;
}
The trackviewmodel is accessible in the SelectedIndexChanged event and everything else was really straight forward, Which looks like this:
private void territoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
string territory = picker.SelectedItem.ToString();
ObservableCollection<Tracks> dah = (ObservableCollection<Tracks>)trackviewmodel.Tracks;
List<string> trackNames = new List<string>();
foreach (var track in dah)
{
if (track.Territory == territory)
trackNames.Add(track.Track);
}
trackPicker.ItemsSource = trackNames;
if(trackNames.Count ==1)
trackPicker.SelectedIndex = 0;
trackPicker.IsEnabled = true;
}
Thanks for the help

Why picker trigger twice onselectedindexchangedevent in xamarin forms

Why picker twice time triggered first time i get the values of Selecteditem second time it seems to be null all. How to resolve this issue.
private void OnSelectedIndexChanged(object sender, EventArgs e)
{
double vatPercent;
object selectedPicker = ((Picker)sender).BindingContext;
Picker picker = ((Picker)sender);
object vatItem = picker.SelectedItem;
int index = picker.SelectedIndex;
if (vatItem != null)
{
VatRate vatRate = vatItem as VatRate;
vatPercent = vatRate.Rate;
}
else
vatPercent = 0;
}
This issue has been reported:
https://github.com/xamarin/Xamarin.Forms/issues/2075
https://github.com/xamarin/Xamarin.Forms/issues/7646
You could try the suggestions below:
Update Xamarin Forms to latest version.
Use the ObservableCollection as ItemSource.

my zend session name spacing does not work

I am new to Zend and very keen to learn, so I would really appreciate some help and guidance.
I am trying to create a 'method in a class' that will save the session variables of product pages visited by members to a site i.e
i,e examplesite com/product/?producttype= 6
I want to save the number 6 in a session variable. I also do not want to have a global session for the entire site; I just want it for selected pages. So, I guess I have to have Zend_Session::start() on the selected page; but I am not clear how this should be done.
Should I instantiate it in the page view page. i.e products page or do this in the indexAction() method for the products page. I have attempted to instantiate it below but it did not work.
public function rememberLastProductSearched()
{ //my attempt to start a session start for this particular page.
Zend_Session::start();
}
$session->productSearchCategory = $this->_request->getParam('product-search-category');
return" $session->productSearchCategory ";
}
else
{
//echo " nothing there
return " $session->productSearchCategory";
//";
}
}
With the rememberLastProductSearched() method I was trying to get the method to first check whether the user had searched for a new product or just arrived at the page by default. i.e whether he had used the get() action to search for a new product. If the answer is no, then I wanted the system to check whether their had been a previous saved session variable. so in procedural syntax it would have gone like this:
if(isset($_Get['producttype']))
{
//$dbc database connection
$producttype = mysqli_real_escape_string($dbc,trim($_GET['producttype']));
}
else
if(isset($_SESSION['producttype'])){
$producttype = mysqli_real_escape_string($dbc,trim($_SESSION['producttype']));
}
Can you please help me with the Zend/oop syntax. I am totally confused how it should be?
you're asking about simple work flow in an action, it should begin something like:
//in any controller
public function anyAction()
{
//open seesion, start will be called if needed
$session = new Zend_Session_Namespace('products');
//get value
$productCategory = $this->getRequest()->getParam('producttype');
//save value to namespace
$session->productType = $productCategory;
//...
}
now to move this off to a separate method you have to pass the data to the method...
protected function rememberLastProductSearched($productType)
{
//open seesion, start will be called if needed
$session = new Zend_Session_Namespace('products');
$session->productType = $productType;
}
So now if you want to test for presence of a value...
//in any controller
public function anyAction()
{
//open seesion, call the namespace whenever you need to access it
$session = new Zend_Session_Namespace('products');
if (!isset($session->productType)) {
$productCategory = $this->getRequest()->getParam('producttype');
//save value to session
$this->rememberLastProductSearched($productCategory)
} else {
$productCategory = $session->productType;
}
}
That's the idea.
Be mindful of your work flow as it can sometimes be very simple to inadvertently overwrite your session values.
$session = new Zend_Session_Namespace("productSearch");
if ($this->getRequest()->getParam('producttype')) { //isset GET param ?
$session->productType = $this->getRequest()->getParam('producttype');
$searchedProductType = $session->productType;
} else { //take the session saved value
if ($session->productType) {
$searchedProductType = $session->productType;
}
}
//now use $searchedProductType for your query

Windows 8 Metro App MediaElement.SetSource (can not change the volume during playback)

I am making Windows 8 Metro style app.
I want to be able to run different sounds at the same time and manage them. For this goals I have created MediaPlayService which should contain methods which allow me to do that.
I found one issue that after "_mediaElement.SetSource()" I can not change volume. I am calling SetVolume and nothing happen.
Initialize(sound);
SetVolume(100);
Play(); --- this sequence works
Initialize(sound);
Play();
SetVolume(100); --- does not work (I can not change the volume during playback)
public void SetVolume(int volume)
{
//_m ediaElement.Volume = Math.Round((double)((double)volume / 100), 2);
double dvolume = Math.Round((double)((double)volume / 100), 2);
_mediaElement.SetValue(MediaElement.VolumeProperty, dvolume);
}
string _mediaPath;
public void Initialize(Sound sound)
{
_mediaElement = new MediaElement();
_mediaPath = sound.FilePath;
_mediaElement.AudioCategory = Windows.UI.Xaml.Media.AudioCategory.Communications;
_mediaElement.IsLooping = true;
_mediaElement.MediaFailed += _mediaElement_MediaFailed;
_mediaElement.RealTimePlayback = true;
}
public async void Play()
{
var pack = Windows.ApplicationModel.Package.Current;
var installedLoction = pack.InstalledLocation;
var storageFile = await installedLoction.GetFileAsync(_mediaPath);
if (storageFile != null)
{
var stream = await storageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
_mediaElement.SetSource(stream, storageFile.ContentType);
_mediaElement.Play();
}
}
Your MediaElement isn't part of the VisualTree of your page. As consequence you have to deal with those strange behaviors like setting the volume or position won't work correctly.
As solution you might create the MediaElement in your XAML file or add it from your code-behind to the VisualTree (something like contentGrid.Children.Add( _mediaElement ). In the latter case you probably have to remove it before navigating to another page else it might happen that it won't play the next time you are navigating back.

AutoCompleteBox and SearchText Clear

This is not a question but my answer to a problem I could not find a solution to on the internet.
I had a problem clearing the SearchText in an MVVM Silverlight application. I could clear clear the SelectedItem and Text but the SearchText was left behind. It is read only and cannot be changed by binding.
Example: AutoCompleteBox with a list of Countries. When the user wants to enter Australia they enter 'au' at this point the list appers with Austria and Australia. The user can then select Australia and move on. At the end of editing they click on a 'Save' button. At this point it is likely that you would want to clear the data forn for entering new data.
Even if you have bindings to the SelectedItem and the Text properties and you set them to 'null' and string.Empty respectively the SearchText property remains and the AutoCompleteBox will not clear but will contain 'au'.
I posted about this all over the internet but could get no answer on the control itself and so I came at it from a different angle which may help someone who ends up frustrated like me.
I am using a Silverlight Navigation template application which uses a NavigationFrame in which to load Silverlight pages. I noticed that if I navigated to another page and returned to my data form the SearchText was cleared. Any values that were bound to properties remained valid, just the SearchText had cleared on all AutoCompleteBoxes. I therefore used the PageConductor method of injecting the NavigationFrame into the ViewModel where I could call the refresh method. I got this method from John Papa's example from the Silverlight Firestarter event , I simply added a Refresh method to the IPageConductor interface so I am now able to call 'PageConductor.Refresh()' which is like reloading the page. I hope this helps someone out there.
var t = ProductCombo.ItemsSource;
ProductCombo.ItemsSource = null;
ProductCombo.Text = string.Empty;
ProductCombo.SelectedValue = null;
//ProductCombo.Text = string.Empty;
ProductCombo.ItemsSource = t;
Try this please.it worked for me
You must clear the property bindeaded to Text inside set part of SelectedItem Binded property, like this:
public string AnalisisText
{
get { return _analisisText; }
set
{
if (_analisisText == value)
{
return;
}
_analisisText = value;
RaisePropertyChanged(AnalisisTextPropertyName);
}
}
public DatosAutoCompletaPedidosDetalleViewDTO AnalisisSelect
{
get { return _analisisSelect; }
set
{
if (_analisisSelect == value)
{
return;
}
_analisisSelect = value;
if (_analisisSelect == null) AnalisisText = "";
RaisePropertyChanged(AnalisisSelectPropertyName);
}
}
So, when you set null to property SelectedItem , the other property will set to "".
The easiest way I've found is to extend the AutoCompleteBox:
public class AutoCompleteBoxClear : AutoCompleteBox
{
public AutoCompleteBoxClear()
{
DataContextChanged += (o, e) =>
{
if (SelectedItem == null)
Text = string.Empty;
};
}
}
Now use your new AutoCompleteBoxClear control in your XAML.
This clears the text only when autocompletebox datacontext changes to null (ie the user clicks add in the dataform.)
Note: I think DataContextChanged is available only in Silverlight 5, but I'd guess that anyone still using Silverlight these days would likely have upgraded by now...
var t = ProductCombo.ItemsSource;
ProductCombo.ItemsSource = null;
ProductCombo.Text = string.Empty;
ProductCombo.SelectedValue = null;
//ProductCombo.Text = string.Empty;
ProductCombo.ItemsSource = t;
Unfotunately this is code-behind and I needed an MVVM solution.
I recently had the same problem with my WPF app. I found out that the solution is not to set the object bound to SelectedItem to null, but to its default value. Took me a while to figure this out. So in your example, it would not be SelectedCountry = null, but SelectedCountry = new SelectedCountry(). In this case the SearchText is cleared also. Check my SO post regarding this matter: Autocompletebox doesn't clear keyboard strokes.
Sure SearchText property is read-only, but we can get the child component of AutoCompleteBox:
var searchText = autoCompBox.GetChildByType<TextBox>(item => item.Name == "Text");
And now we can reset SearchText via Text property of TextBox-component:
if (searchText != null) searchText.Text = string.Empty;
In C# 6.0 it is more laconically:
autoCompBox.GetChildByType<TextBox>(item => item.Name == "Text")?.Text = string.Empty;