Okay, I am trying to set up a settings page for my app. On this page I
want the user to select a series of options for what fields to display
on another page.
I have a settings system overloaded using the using Xamarin.Essentials;
extensions, so I can handle lookup, generation, and clearing of various
settings. I will then later in the target page use these functions to
alter various IsVisible options.
When a switch is toggled (or eve checkbox checked unchecked) I want the StateChanged
event to fire and run my custom callback using the dynamic data from
the event to modify the internal stored settings for the app.
I am thinking that it should go something like this...
This is a dataclass to store a group of settings to be passed to the treeview.
public class SettingsOption : EventParent, INotifyPropertyChanged
{
/// <summary>
/// private storage Displayname
/// </summary>
private string displayname;
/// <summary>
/// private storage ImageIcon
/// </summary>
private ImageSource imageIcon;
/// <summary>
/// private storage PropertiesGroup
/// </summary>
private ObservableCollection<SettingsOption> propertiesGroup;
/// <summary>
/// private storage PropertyName
/// </summary>
private string propertyName;
/// <summary>
/// Gets or sets the value for Displayname
/// </summary>
public string Displayname
{
get => displayname;
set
{
SetProperty(ref displayname, value, nameof(Displayname));
OnPropertyChanged(nameof(Displayname));
}
}
/// <summary>
/// Gets or sets the value for ImageIcon
/// </summary>
public ImageSource ImageIcon
{
get => imageIcon;
set
{
SetProperty(ref imageIcon, value, nameof(ImageIcon));
OnPropertyChanged(nameof(ImageIcon));
}
}
/// <summary>
/// Gets or sets the value for PropertiesGroup
/// </summary>
public ObservableCollection<SettingsOption> PropertiesGroup
{
get => propertiesGroup;
set
{
SetProperty(ref propertiesGroup, value, nameof(PropertiesGroup));
OnPropertyChanged(nameof(PropertiesGroup));
}
}
/// <summary>
/// Gets or sets the value for PropertyName
/// </summary>
public string PropertyName
{
get => propertyName;
set
{
SetProperty(ref propertyName, value, nameof(PropertyName));
OnPropertyChanged(nameof(PropertyName));
}
}
/// <summary>
/// Defines the PropertyChanged
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// The RaisedOnPropertyChanged
/// </summary>
/// <param name="_PropertyName"> The _PropertyName <see cref="string" /> </param>
public void RaisedOnPropertyChanged(string _PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(_PropertyName));
}
}
This is a function I created in order to make a lookup and toggle of the setting possible
private bool BounceSetting(string settingName)
{
if (!AppSettingsFunctions.CheckKey(settingName))
{
AppSettingsFunctions.SaveSettingData(settingName, true);
}
else
{
//Save the new setting as a process of the inverse of getting the existing data
AppSettingsFunctions.SaveSettingData(settingName, !AppSettingsFunctions.GetBoolSetting(settingName));
}
}
I want to then be able to setup the treeview like this.
private void BuildSettingsTreegroups()
{
tvSettingsOptions.ChildPropertyName = "PropertiesGroup";
tvSettingsOptions.ItemTemplateContextType = ItemTemplateContextType.Node;
tvSettingsOptions.IsAnimationEnabled = true;
tvSettingsOptions.Indentation = 20;
tvSettingsOptions.AutoExpandMode = Syncfusion.TreeView.Engine.AutoExpandMode.RootNodesExpanded;
tvSettingsOptions.ItemsSource = SettingsGroup;
tvSettingsOptions.ItemTemplate = new DataTemplate(() =>
{
var displayName = new Label { VerticalTextAlignment = TextAlignment.Center };
var slEntry = new StackLayout { Orientation = StackOrientation.Horizontal };
var optionIcon = new Image { HeightRequest = 26, WidthRequest = 26 };
var swSetting = new SfSwitch();
optionIcon.SetBinding(Image.SourceProperty, new Binding("Content.ImageIcon"));
displayName.SetBinding(Label.TextProperty, new Binding("Content.Displayname"));
swSetting.SetBinding(SfSwitch.IsOnProperty, AppSettingsFunction.GetBoolSetting("Content.PropertyName"));
swSetting.StateChanged += (s, e) => BounceSetting("Content.PropertyName");
slEntry.Children.Add(optionIcon);
slEntry.Children.Add(displayName);
slEntry.Children.Add(swSetting);
return slEntry;
});
}
The problem is that the swSetting binding. To get the current setting the app needs to call the settings function I overloaded in my AppSettingsFunction class.
With the above code I could theoretically build my settings page like this then building an ObservableCollection<SettingsOptions> object that I populate my settings into like this ...
var mainOptionsgroup = new SettingsOption(); var inventoryOptions = new SettingsOption();
inventoryOptions.Displayname = "Select Inventory options to hide"; inventoryOptions.ImageIcon = "InventoryIcon"; inventoryOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "Size", PropertyName = "inv_ShowSize" }); inventoryOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "SKU", PropertyName = "inv_SKU" }); inventoryOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "Price", PropertyName = "inv_Price" }); var supplierPageOptions = new SettingsOption(); supplierPageOptions.Displayname = "Select Supplier options to hide"; supplierPageOptions.ImageIcon = "Suppliers"; supplierPageOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "Account#", PropertyName = "sup_Account" }); supplierPageOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "Phone Number", PropertyName = "sup_Phone" }); supplierPageOptions.PropertiesGroup.Add(new SettingsOption { Displayname = "Address", PropertyName = "sup_Address" });
mainOptionsgroup.Displayname = "Settings"; mainOptionsgroup.PropertiesGroup.Add(inventoryOptions); mainOptionsgroup.PropertiesGroup.Add(supplierPageOptions);
Any ideas would be most appreciated!
Thanks!
Here is what I had to do to make this work
For the ItemsTemplate I simply made the sfSwitch use it's AutomationIdProperty hold the value of the property, then look it up using the lambda for calling BounceSetting(((SfSwitch)s).AutomationId);..
I added a Property to my SettingsOption class for LastState so that I can lookup the existing value and send it in the data.
tvSettingsOptions.ItemTemplate = new DataTemplate(() =>
{
try
{
var slEntry = new StackLayout { Orientation = StackOrientation.Horizontal };
var optionIcon = new Image { HeightRequest = 26, WidthRequest = 26 };
var displayName = new Label { VerticalTextAlignment = TextAlignment.Center };
var swSetting = new SfSwitch();
optionIcon.SetBinding(Image.SourceProperty, new Binding("Content.ImageIcon"));
displayName.SetBinding(Label.TextProperty, new Binding("Content.Displayname"));
swSetting.SetBinding(SfSwitch.AutomationIdProperty, new Binding("Content.PropertyName"));
swSetting.SetBinding(SfSwitch.IsOnProperty, new Binding("Content.LastState"));
swSetting.StateChanged += (s, e) => BounceSetting(((SfSwitch)s).AutomationId);
slEntry.Children.Add(optionIcon);
slEntry.Children.Add(displayName);
slEntry.Children.Add(swSetting);
var grid = new Grid();
grid.Children.Add(slEntry);
return grid;
}
catch (Exception ex)
{
Debug.WriteLine($"SettingsPage.xaml.cs->BuildSettingsTreegroups()->{ex.StackTrace}->{ex.Message}.{Environment.NewLine}{ex.InnerException}.{Environment.NewLine}{ex.Data}");
return new Label { Text = "ERROR" };
}
});
Thanks anyhow!