Add project files.

This commit is contained in:
Andy Howard
2021-05-05 15:36:28 +01:00
parent 949836d24c
commit a4cf706eb3
353 changed files with 60029 additions and 0 deletions
@@ -0,0 +1,49 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.App
{
//=======================================================================
public abstract class SaxApplication : Application
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
protected SaxApplication ()
{
// Xamarin Essentials version tracking.
VersionTracking.Track();
// Log environment.
SaLogger.Debug("AppInfo.AppName: " + AppInfo.Name);
SaLogger.Debug("AppInfo.PackageName: " + AppInfo.PackageName);
SaLogger.Debug("AppInfo.Version: " + AppInfo.VersionString);
SaLogger.Debug("AppInfo.Build: " + AppInfo.BuildString);
SaLogger.Debug("DeviceWidth: " + DeviceWidth);
SaLogger.Debug("DeviceHeight: " + DeviceHeight);
SaLogger.Debug("DeviceDensity: " + DeviceDisplay.MainDisplayInfo.Density);
}
//-------------------------------------------------------------------
// Properties.
// Device screen size and orientation.
public static bool Landscape => DeviceWidth > DeviceHeight;
public static double DeviceWidth => DeviceDisplay.MainDisplayInfo.Width;
public static double DeviceHeight => DeviceDisplay.MainDisplayInfo.Height;
public static double MinDeviceDimension => Math.Min(DeviceWidth, DeviceHeight);
public static double MaxDeviceDimension => Math.Max(DeviceWidth, DeviceHeight);
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Base
{
//=======================================================================
public class SaxComponents
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private bool readOnly = false;
//-------------------------------------------------------------------
// Construction.
public SaxComponents ()
{
}
//-------------------------------------------------------------------
// Properties.
public bool ReadOnly
{
get { return readOnly; }
set { if (readOnly == value) return; readOnly = value; SetControlsReadOnly(); }
}
public bool Changed { get; protected set; } = false;
//-------------------------------------------------------------------
// C o n f i g u r e C o m p o n e n t s
//-------------------------------------------------------------------
protected virtual void ConfigureComponents ()
{
}
//-------------------------------------------------------------------
// C o n t r o l A c t i v i t y
//-------------------------------------------------------------------
protected virtual void SetControlActivity ()
{
}
protected virtual void SetControlsReadOnly ()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxButton : Button
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxButton ()
{
DefaultFontSize = FontSize;
}
//-------------------------------------------------------------------
// Properties.
public double DefaultFontSize { get; }
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,221 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxDatePicker : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private bool allowInvalidDate = false;
private bool invalidDate = true;
private DateTime previousDate = DateTime.MinValue;
private SaxStackLayout controlLayout = new SaxStackLayout() { Orientation=StackOrientation.Horizontal, HorizontalOptions=LayoutOptions.Fill };
private DatePicker pickerDate = new DatePicker() { IsVisible = false };
private SaxEntry entryDate = new SaxEntry() { HorizontalOptions=LayoutOptions.FillAndExpand, VerticalOptions=LayoutOptions.Fill };
private SaxLabel labelResetDate = new SaxLabel() { Text="X", FontAttributes=FontAttributes.Bold, TextColor=Color.Red, HorizontalOptions=LayoutOptions.Center, VerticalTextAlignment=TextAlignment.Center };
//-------------------------------------------------------------------
// Construction.
public SaxDatePicker ()
{
// Initialise controls.
// Date picker. Hidden but used to display calendar.
DefaultFontSize = pickerDate.FontSize;
pickerDate.Format = "dd-MMM-yyyy";
pickerDate.DateSelected += PickerDate_DateSelected;
// Date display entry.
entryDate.FontSize = pickerDate.FontSize;
entryDate.FontFamily = pickerDate.FontFamily;
entryDate.FontAttributes = pickerDate.FontAttributes;
entryDate.TextColor = pickerDate.TextColor;
entryDate.Focused += EntryDate_Focused;
// 'Reset' date label - to invalidate the date value.
labelResetDate.FontSize = pickerDate.FontSize;
labelResetDate.FontFamily = pickerDate.FontFamily;
// 'Reset' label tap gesture.
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += LabelValidDate_Tapped;
labelResetDate.GestureRecognizers.Add(tapGestureRecognizer);
// Initialise layout.
Content = controlLayout;
controlLayout.Children.Add(pickerDate);
controlLayout.Children.Add(entryDate);
controlLayout.Children.Add(labelResetDate);
RefreshDateDisplay();
}
//-------------------------------------------------------------------
// Properties.
// Configuration.
public Boolean AllowInvalid
{
get { return allowInvalidDate; }
set
{
if (allowInvalidDate = value) return;
allowInvalidDate = value;
if (!allowInvalidDate) invalidDate = false;
RefreshDateDisplay();
}
}
public string Format
{
get { return pickerDate.Format; }
set
{
if (pickerDate.Format.Equals(value)) return;
pickerDate.Format = value;
}
}
public DateTime MinimumDate
{
get { return pickerDate.MinimumDate; }
set { pickerDate.MinimumDate = value; }
}
public DateTime MaximumDate
{
get { return pickerDate.MaximumDate; }
set { pickerDate.MaximumDate = value; }
}
//-------------------------------------------------------------------
// Date value.
public DateTime Date
{
get
{
if (invalidDate) return DateTime.MinValue;
return pickerDate.Date;
}
set
{
if (Date.Equals(value)) return;
if (!DateUtil.IsValid(value))
{
invalidDate = true;
pickerDate.Date = DateTime.Today;
}
else
{
invalidDate = false;
pickerDate.Date = value;
}
previousDate = value;
}
}
public String FormattedDate { get { return !invalidDate ? DateUtil.Format(Date, pickerDate.Format) : ""; } }
//-------------------------------------------------------------------
// Font.
public double DefaultFontSize { get; }
public double FontSize
{
get { return pickerDate.FontSize; }
set
{
if (pickerDate.FontSize == value) return;
pickerDate.FontSize = value;
entryDate.FontSize = value;
}
}
public String FontFamily
{
get { return pickerDate.FontFamily; }
set
{
if (pickerDate.FontFamily == value) return;
pickerDate.FontFamily = value;
entryDate.FontFamily = value;
}
}
public FontAttributes FontAttributes
{
get { return pickerDate.FontAttributes; }
set
{
if (pickerDate.FontAttributes == value) return;
pickerDate.FontAttributes = value;
entryDate.FontAttributes = value;
}
}
public Color TextColor
{
get { return pickerDate.TextColor; }
set
{
if (pickerDate.TextColor == value) return;
pickerDate.TextColor = value;
entryDate.TextColor = value;
}
}
//-------------------------------------------------------------------
// Utilities.
private void RefreshDateDisplay()
{
if (allowInvalidDate)
{
pickerDate.IsVisible = false;
entryDate.IsVisible = true;
labelResetDate.IsVisible = true;
}
else
{
pickerDate.IsVisible = true;
entryDate.IsVisible = false;
labelResetDate.IsVisible = false;
}
String dateValue = "";
if (!invalidDate)
dateValue = DateUtil.Format(Date, pickerDate.Format);
entryDate.Text = dateValue;
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
private void PickerDate_DateSelected (object sender, DateChangedEventArgs e)
{
// Date has changed in control.
invalidDate = !DateUtil.IsValid(e.NewDate);
RefreshDateDisplay();
if (DateSelected != null) DateSelected.Invoke(sender, e);
}
public event EventHandler<DateChangedEventArgs> DateSelected;
//-------------------------------------------------------------------
private void EntryDate_Focused (object sender, FocusEventArgs e)
{
// Control has gained focus.
entryDate.Unfocus();
pickerDate.Focus();
invalidDate = false;
RefreshDateDisplay();
}
//-------------------------------------------------------------------
private void LabelValidDate_Tapped (object sender, EventArgs e)
{
// 'Valid' label tapped.
if (invalidDate) return;
invalidDate = true;
DateTime oldDate = previousDate;
RefreshDateDisplay();
if (DateSelected != null) DateSelected.Invoke(sender, new DateChangedEventArgs(oldDate, Date));
previousDate = Date;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,161 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxDateTimePicker : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
// Control layout.
private SaxStackLayout layoutControl = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal };
private SaxDatePicker pickerDate = new SaxDatePicker();
private SaxLabel labelTimePrefix = new SaxLabel();
private SaxTimePicker pickerTime = new SaxTimePicker();
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxDateTimePicker ()
{
DefaultFontSize = pickerDate.FontSize;
// Configure components.
Content = layoutControl;
layoutControl.Children.Add(pickerDate);
layoutControl.Children.Add(pickerTime);
// Control events.
pickerDate.DateSelected += PickerDate_DateSelected;
pickerTime.TimeChanged += PickerTime_TimeChanged;
}
//-------------------------------------------------------------------
// Properties.
public string DateFormat
{
get { return pickerDate.Format; }
set
{
if (pickerDate.Format.Equals(value)) return;
pickerDate.Format = value;
}
}
public DateTime MinimumDate
{
get { return pickerDate.MinimumDate; }
set { pickerDate.MinimumDate = value; }
}
public DateTime MaximumDate
{
get { return pickerDate.MaximumDate; }
set { pickerDate.MaximumDate = value; }
}
public string TimeFormat
{
get { return pickerTime.Format; }
set
{
if (pickerTime.Format.Equals(value)) return;
pickerTime.Format = value;
}
}
// Control value.
public DateTime DateTime
{
get { return pickerDate.Date.Date + pickerTime.Time; }
set
{
if (DateTime.CompareTo(value) == 0) return;
pickerDate.Date = value.Date;
pickerTime.Time = value - value.Date;
}
}
public String DateTimeDelim { get; set; } = " ";
public String FormattedDateTime { get { return pickerDate.FormattedDate + DateTimeDelim + pickerTime.FormattedTime; } }
// Styling.
public double DefaultFontSize { get; }
public double FontSize
{
get { return pickerDate.FontSize; }
set { if (pickerDate.FontSize == value) return; pickerDate.FontSize = value; pickerTime.FontSize = value; labelTimePrefix.FontSize = value; }
}
/// <summary>Amount of space between date and time pickers.</summary>
public double ControlSpacing
{
get { return layoutControl.Spacing; }
set { if (layoutControl.Spacing == value) return; layoutControl.Spacing = value; }
}
public String TimePickerPrefixText
{
get { return labelTimePrefix.Text; }
set { value = StringUtil.TrimAll(value); if (labelTimePrefix.Text.Equals(value)) return; labelTimePrefix.Text = value; ConfigureComponents(); }
}
//-------------------------------------------------------------------
// C o n f i g u r e C o m p o n e n t s
//-------------------------------------------------------------------
protected override void ConfigureComponents ()
{
base.ConfigureComponents();
// Time Picker prefix label text.
if (!StringUtil.IsEmpty(TimePickerPrefixText))
{
// Label has text - ensure label is in the layout.
if (!layoutControl.Children.Contains(labelTimePrefix))
{
// Label will be inserted before the time picker.
int insertIdx = layoutControl.Children.IndexOf(pickerTime);
layoutControl.Children.Insert(insertIdx, labelTimePrefix);
}
}
else
{
// Blank label text - remove label from layout.
if (layoutControl.Children.Contains(labelTimePrefix))
layoutControl.Children.Remove(labelTimePrefix);
}
}
//-------------------------------------------------------------------
// C o n t r o l A c t i v i t y
//-------------------------------------------------------------------
protected override void SetControlActivity ()
{
base.SetControlActivity();
}
protected override void SetControlsReadOnly ()
{
base.SetControlsReadOnly();
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
private void PickerDate_DateSelected (object sender, DateChangedEventArgs e)
{
if (DateSelected != null) DateSelected.Invoke(sender, e);
}
public event EventHandler<DateChangedEventArgs> DateSelected;
//-------------------------------------------------------------------
private void PickerTime_TimeChanged (object sender, SaxTimePicker.TimeChangedEventArgs e)
{
if (TimeChanged != null) TimeChanged.Invoke(sender, e);
}
public event EventHandler<SaxTimePicker.TimeChangedEventArgs> TimeChanged;
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,77 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxEditor : Editor
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private bool trimTextOnCompletion = true;
private int NumberOfLinesPrevious = 0;
//-------------------------------------------------------------------
// Construction.
public SaxEditor ()
{
DefaultFontSize = FontSize;
Text = "";
TextChanged += SaxEditor_TextChanged;
Completed += SaxEditor_Completed;
}
//-------------------------------------------------------------------
// Properties.
public double DefaultFontSize { get; }
public bool TrimText
{
get { return trimTextOnCompletion; }
set
{
if (trimTextOnCompletion == value) return;
trimTextOnCompletion = value;
}
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
// Key Press event is not supported directly in Xamarin.
// Requires O/S specific implementation.
// See: Sarand.LogisticsMgr.Mobile.Droid.Forms.Renderers.SlmEditorRenderer
public void OnKeyPress_Enter ()
{
// Resize control based on entered text.
InvalidateMeasure();
}
//-------------------------------------------------------------------
private void SaxEditor_TextChanged (object sender, TextChangedEventArgs e)
{
// If the number of lines of text has changed, resize the control.
int NumberOfLines = StringUtil.EmptyOnNull(Text).Split('\n').Length;
if (NumberOfLines != NumberOfLinesPrevious)
// Resize control based on entered text.
InvalidateMeasure();
NumberOfLinesPrevious = NumberOfLines;
}
private void SaxEditor_Completed (object sender, EventArgs e)
{
if (trimTextOnCompletion)
Text = Text.Trim();
// Resize control based on entered text.
InvalidateMeasure();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,152 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxEntry : Entry
{
//-------------------------------------------------------------------
// Definitions.
public enum TextCaseType
{
Normal,
Upper,
Lower,
Title
}
//-------------------------------------------------------------------
// Data members.
private bool trimTextOnCompletion = true;
private TextInfo textInfo = CultureInfo.CurrentCulture.TextInfo;
private TextCaseType textCase = TextCaseType.Normal;
private bool numericOnly = false;
private byte decimals = 0;
//-------------------------------------------------------------------
// Construction.
public SaxEntry ()
{
DefaultFontSize = FontSize;
TextChanged += SaxEntry_TextChanged;
Completed += SaxEntry_Completed;
}
//-------------------------------------------------------------------
// Properties.
public bool TrimText
{
get { return trimTextOnCompletion; }
set
{
if (trimTextOnCompletion == value) return;
trimTextOnCompletion = value;
}
}
public double DefaultFontSize { get; }
public TextCaseType TextCase
{
get { return textCase; }
set
{
if (textCase == value) return;
textCase = value;
FormatText();
}
}
public bool NumericOnly
{
get { return numericOnly; }
set
{
if (numericOnly == value) return;
numericOnly = value;
Keyboard = Keyboard.Numeric;
FormatText();
}
}
public byte Decimals
{
get { return decimals; }
set
{
if (numericOnly && decimals == value) return;
numericOnly = true;
decimals = value;
Keyboard = Keyboard.Numeric;
FormatText();
}
}
//-------------------------------------------------------------------
// F o r m a t T e x t
//-------------------------------------------------------------------
private void FormatText (bool trimText = false)
{
String fn = GetType().Name + ".FormatText";
String originalText = Text;
String formattedText = originalText;
if (StringUtil.IsEmpty(formattedText)) return;
if (trimText)
formattedText = StringUtil.TrimAll(formattedText);
if (numericOnly)
{
if (decimals > 0)
{
decimal value = StringUtil.ToDecimal(formattedText);
if (value != 0.0m)
formattedText = value.ToString("N" + decimals);
else if (!formattedText.Equals("0"))
formattedText = "";
}
else
{
long value = StringUtil.ToLong(formattedText);
if (value != 0)
formattedText = value.ToString();
else if (!formattedText.Equals("0"))
formattedText = "";
}
}
else
{
if (textCase == TextCaseType.Upper)
formattedText = textInfo.ToUpper(formattedText);
else if (textCase == TextCaseType.Lower)
formattedText = textInfo.ToLower(formattedText);
else if (textCase == TextCaseType.Title)
formattedText =
StringUtil.ToTitleCase(formattedText, textInfo);
}
if (!originalText.Equals(formattedText))
{
SaLogger.Debug(fn + " Text: " + originalText + ". Formatted: " + formattedText);
Text = formattedText;
}
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
private void SaxEntry_TextChanged (object sender, TextChangedEventArgs e)
{
FormatText();
}
private void SaxEntry_Completed (object sender, EventArgs e)
{
FormatText(trimTextOnCompletion);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxImageButton : ImageButton
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxImageButton ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxLabel : Label
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxLabel ()
{
DefaultFontSize = FontSize;
Text = "";
}
//-------------------------------------------------------------------
// Properties.
public double DefaultFontSize { get; }
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,171 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using Sarand.Net.Standard.Base.Utils;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxPicker : Picker
{
//-------------------------------------------------------------------
// Definitions.
public class SlmPickerItem
{
public SysId Id { get; set; } = new SysId();
public String Code { get; set; } = "";
public String Caption { get; set; } = "";
public Object Object { get; set; }
public override string ToString ()
{
return Caption;
}
}
//-------------------------------------------------------------------
// Data members.
private readonly List<SlmPickerItem> pickerItems = new List<SlmPickerItem>();
//-------------------------------------------------------------------
// Construction.
public SaxPicker ()
{
DefaultFontSize = FontSize;
}
//-------------------------------------------------------------------
// Properties.
public double DefaultFontSize { get; }
public bool BeingPopulated { get; protected set; } = false;
//-------------------------------------------------------------------
// P o p u l a t e I t e m s
//-------------------------------------------------------------------
/// <summary>
/// Does the list contain an item with the same Id.
/// <para>NB Invalid Id values are matched.</para>
/// </summary>
public bool ContainsItemId (SysId id)
{
return pickerItems.Exists(item => SysId.ToInt(item.Id) == SysId.ToInt(id));
}
/// <summary>
/// Does the list contain an item with the same code.
/// <para>NB Codes are case-insensitive.</para>
/// </summary>
public bool ContainsItemCode (String code)
{
return pickerItems.Exists(item => item.Code.EqualsCI(code));
}
//-------------------------------------------------------------------
/// <summary>Remove all items from the picker.</summary>
public void ClearItems ()
{
Items.Clear();
ItemsSource = null;
pickerItems.Clear();
}
/// <summary>Replace existing picker item list.</summary>
public void SetItems (List<SlmPickerItem> pickerItems)
{
ClearItems();
this.pickerItems.AddRange(pickerItems);
RefreshPickerItems();
}
//-------------------------------------------------------------------
/// <summary>
/// Add an item identified by a SysId value.
/// <para>NB Fails if an item already exists with the same id.</para>
/// </summary>
public bool AddItem (SysId id, String caption)
{
if (ContainsItemId(id)) return false;
pickerItems.Add(new SlmPickerItem() { Id = id, Caption = caption });
RefreshPickerItems();
return ContainsItemId(id);
}
/// <summary>
/// Add an item identified by a code value.
/// <para>NB Fails if an item already exists with the same case-insensitive code.</para>
/// </summary>
public bool AddItem (String code, String caption)
{
if (ContainsItemCode(code)) return false;
pickerItems.Add(new SlmPickerItem() { Code = code, Caption = caption });
RefreshPickerItems();
return ContainsItemCode(code);
}
//-------------------------------------------------------------------
private void RefreshPickerItems ()
{
//SetBinding(Picker.ItemsSourceProperty, BindableProperty.Create());
//ItemDisplayBinding = new Binding("Caption");
// Picker items doesn't automatically keep up to date with teh ItemsSource list.
// So clear it and reset to force the refresh.
ItemsSource = null;
ItemsSource = pickerItems;
}
//-------------------------------------------------------------------
// I t e m S e l e c t i o n
//-------------------------------------------------------------------
public SlmPickerItem SelectedPickerItem
{
get
{
object selectedItem = SelectedItem;
if (selectedItem == null || !(selectedItem is SlmPickerItem)) return null;
return (selectedItem as SlmPickerItem);
}
set
{
if (SelectedPickerItem == value) return;
if (ItemsSource == null || !ItemsSource.Contains(value)) return;
base.SelectedItem = value;
}
}
public SysId SelectedItemId
{
get
{
SlmPickerItem selectedPickerItem = SelectedPickerItem;
return selectedPickerItem != null ? selectedPickerItem.Id : new SysId();
}
set
{
SelectedPickerItem = pickerItems.Find(item => item.Id.Equals(value));
}
}
public String SelectedItemCode
{
get
{
SlmPickerItem selectedPickerItem = SelectedPickerItem;
return selectedPickerItem != null ? selectedPickerItem.Code : "";
}
set
{
SelectedPickerItem = pickerItems.Find(item => item.Code.EqualsCI(value));
}
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
// Picker population completed.
public class PopulatedEventArgs : EventArgs { }
public delegate void PopulatedEventHandler (object sender, PopulatedEventArgs e);
/// <summary>Picker population completed event handler.</summary>
public event PopulatedEventHandler Populated;
protected void InvokePopulatedEvent ()
{
if (Populated != null) Populated.Invoke(this, new PopulatedEventArgs() { });
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,188 @@
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Panels;
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxTabControl : ContentView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private readonly List<SaxTabPanel> tabPanels = new List<SaxTabPanel>();
private short currentTabIdx = -1;
// Main layout to host header and body.
private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = StackOrientation.Vertical };
// Header layout - horizontal row.
private SaxFlexLayout headerPanel = new SaxFlexLayout() { Direction = FlexDirection.Row, AlignItems = FlexAlignItems.Center, JustifyContent = FlexJustify.Start, HorizontalOptions = LayoutOptions.Start };
// Body - Content view to host tab panel.
private SaxContentView bodyPanel = new SaxContentView();
//-------------------------------------------------------------------
// Construction.
public SaxTabControl ()
{
// Main layout - vertical stack with two rows.
// 1. Header - tab panel captions.
// 2. Body - current tab panel.
VerticalOptions = LayoutOptions.FillAndExpand;
//BackgroundColor = Color.LightSkyBlue;
mainLayout.VerticalOptions = LayoutOptions.FillAndExpand;
mainLayout.Spacing = 2.0;
Content = mainLayout;
// Header panel - tab captions.
//headerPanel.HorizontalOptions = LayoutOptions.Fill;
mainLayout.Children.Add(headerPanel);
// Default label font size.
DefaultHeaderFontSize = new Label().FontSize;
HeaderFontSize = DefaultHeaderFontSize;
// Body panel.
bodyPanel.HorizontalOptions = LayoutOptions.Fill;
bodyPanel.VerticalOptions = LayoutOptions.FillAndExpand;
bodyPanel.BackgroundColor = Color.LightYellow;
mainLayout.Children.Add(bodyPanel);
}
//-------------------------------------------------------------------
// Properties.
// Header.
public Color HeaderBackgroundColor { get { return headerPanel.BackgroundColor; } set { headerPanel.BackgroundColor = value; } }
public Color CaptionBackgroundColor { get; set; } = Color.Transparent;
public double DefaultHeaderFontSize { get; }
public double HeaderFontSize { get; set; }
public double HeaderMarginBottom
{
get { return mainLayout.Spacing; }
set { if (mainLayout.Spacing == value) return; mainLayout.Spacing = value; }
}
public Thickness HeaderPadding
{
get { return mainLayout.Padding; }
set { if (mainLayout.Padding == value) return; mainLayout.Padding = value; }
}
public Thickness HeaderCaptionPadding { get; set; } = new Thickness(12.0, 4.0);
public double HeaderCaptionSpacing { get; set; } = 4.0;
// Tab panels.
public Color BodyBackgroundColor { get { return bodyPanel.BackgroundColor; } set { bodyPanel.BackgroundColor = value; } }
public int PanelCount { get { return tabPanels.Count; } }
public short TabPanelIndex
{
get { return currentTabIdx; }
set { ChangeTabPanel(value); }
}
//-------------------------------------------------------------------
// T a b P a n e l s
//-------------------------------------------------------------------
public void ClearPanels ()
{
tabPanels.Clear();
RefreshLayout();
}
public void AddPanel (String caption, SaxContentView panel)
{
AddPanel(new SaxTabPanel(caption, panel));
}
public void AddPanel (SaxTabPanel tabPanel)
{
AddPanels(new List<SaxTabPanel>() { tabPanel });
}
public void AddPanels (IEnumerable<SaxTabPanel> tabPanels)
{
this.tabPanels.AddRange(tabPanels);
RefreshLayout();
}
//-------------------------------------------------------------------
// R e f r e s h L a y o u t
//-------------------------------------------------------------------
private void RefreshLayout ()
{
// Clear existing components.
headerPanel.Children.Clear();
bodyPanel.Content = null;
// Add each Tab panel in turn.
for (short tabPanelIdx = 0; tabPanelIdx < tabPanels.Count; tabPanelIdx++)
{
short tabPanelIdx_Local = tabPanelIdx; // Loop closure.
SaxTabPanel tabPanel = tabPanels[tabPanelIdx];
// Header caption.
SaxContentView captionPanel = new SaxContentView()
{
Padding = HeaderCaptionPadding,
BackgroundColor = CaptionBackgroundColor,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
if (tabPanelIdx > 0)
captionPanel.Margin = new Thickness(HeaderCaptionSpacing, 0, 0, 0);
SaxLabel captionLabel = new SaxLabel()
{
Text = tabPanel.Caption,
FontSize = HeaderFontSize
};
captionPanel.Content = captionLabel;
headerPanel.Children.Add(captionPanel);
// Tap Gesture.
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => { ChangeTabPanel(tabPanelIdx_Local); };
captionPanel.GestureRecognizers.Add(tapGestureRecognizer);
}
// Current tab retains previous value if still valid (in panel range),
// is restricted to the range 0 to number of panels - 1 if there are panels,
// or -1 if no panels.
currentTabIdx = (short)(tabPanels.Count > 0 ? Math.Max(0, Math.Min(tabPanels.Count - 1, currentTabIdx)) : -1);
if (tabPanels.Count > 0)
ChangeTabPanel(currentTabIdx);
}
//-------------------------------------------------------------------
// C h a n g e T a b P a n e l
//-------------------------------------------------------------------
private void ChangeTabPanel (short tabPanelIdx)
{
// Validate requested panel index.
if (tabPanelIdx < 0 || tabPanelIdx >= tabPanels.Count)
throw new IndexOutOfRangeException("Tab panel index must be between 0 & " + (tabPanels.Count - 1) + ". Supplied value: " + tabPanelIdx);
// Highlight selected tab panel header caption.
for (short headerPanelIdx = 0; headerPanelIdx < headerPanel.Children.Count; headerPanelIdx++)
{
View headerPanelView = headerPanel.Children[headerPanelIdx];
Label headerPanelLabel = (headerPanelView as Label);
if (headerPanelLabel == null && headerPanelView is ContentView)
headerPanelLabel = ((headerPanelView as ContentView).Content as Label);
if (headerPanelLabel != null)
{
if (headerPanelIdx == tabPanelIdx)
headerPanelLabel.FontAttributes = FontAttributes.Bold;
else headerPanelLabel.FontAttributes = FontAttributes.None;
}
}
// Display selected tab panel.
bodyPanel.Content = tabPanels[tabPanelIdx];
currentTabIdx = tabPanelIdx;
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,53 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxTimePicker : TimePicker
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxTimePicker ()
{
DefaultFontSize = FontSize;
Format = "HH:mm";
}
//-------------------------------------------------------------------
// Properties.
public String FormattedTime { get { return DateUtil.Format(DateTime.Today + Time, Format); } }
// Styling.
public double DefaultFontSize { get; }
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
public class TimeChangedEventArgs : EventArgs { };
public event EventHandler<TimeChangedEventArgs> TimeChanged;
protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
if (propertyName.EqualsCI(TimePicker.TimeProperty.PropertyName))
{
base.OnPropertyChanged(propertyName);
if (TimeChanged != null) TimeChanged.Invoke(this, new TimeChangedEventArgs());
return;
}
base.OnPropertyChanged(propertyName);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,99 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Controls
{
//=======================================================================
public class SaxWebView : WebView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
public String html = "";
private HtmlWebViewSource htmlSource;
private UrlWebViewSource aboutBlankSource = new UrlWebViewSource() { Url = "about:blank" };
// Managers.
//-------------------------------------------------------------------
// Construction.
public SaxWebView ()
{
// Events.
Navigating += WebView_Navigating;
Navigated += WebView_Navigated;
// HTML source.
htmlSource = new HtmlWebViewSource() { Html = html };
Source = aboutBlankSource;
}
//-------------------------------------------------------------------
// Properties.
// HTML Panel.
public static String AppActionPrefix => "App:";
public String Html
{
get { return html; }
set
{
Source = aboutBlankSource;
htmlSource.Html = null;
html = value;
htmlSource.Html = html;
Source = htmlSource;
}
}
//-------------------------------------------------------------------
// N a v i g a t i o n
//-------------------------------------------------------------------
public class AppNavigatingEventArgs : EventArgs
{
public String AppAction { get; set; }
}
public delegate void AppNavigatingEventHandler (object sender, AppNavigatingEventArgs e);
public event AppNavigatingEventHandler AppNavigating;
private void OnAppNavigating (String appAction)
{
if (AppNavigating != null) AppNavigating.Invoke(this, new AppNavigatingEventArgs() { AppAction = appAction });
}
private String GetAppAction (String location)
{
if (!location.StartsWithCI(AppActionPrefix)) return "";
return location.Right(location.Length - AppActionPrefix.Length);
}
//-------------------------------------------------------------------
// C o n t r o l E v e n t s
//-------------------------------------------------------------------
private void WebView_Navigating (object sender, WebNavigatingEventArgs e)
{
String appAction = GetAppAction(e.Url);
SaLogger.Debug("SaxWebView_Navigating URL: "+e.Url+". App action: "+ appAction);
if (!StringUtil.IsEmpty(appAction))
{
e.Cancel = true;
OnAppNavigating(appAction);
}
}
private void WebView_Navigated (object sender, WebNavigatedEventArgs e)
{
SaLogger.Debug("SaxWebView_Navigated URL: " + e.Url);
String appAction = GetAppAction(e.Url);
if (!StringUtil.IsEmpty(appAction))
{
Source = htmlSource;
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Layouts
{
//=======================================================================
public class SaxAbsoluteLayout : AbsoluteLayout
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxAbsoluteLayout ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Layouts
{
//=======================================================================
public class SaxFlexLayout : FlexLayout
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxFlexLayout ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Templates
{
//=======================================================================
public class SaxGrid : Grid
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxGrid ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// G r i d E v e n t s
//-------------------------------------------------------------------
protected override void OnParentSet ()
{
base.OnParentSet();
}
//-------------------------------------------------------------------
protected override void OnPropertyChanging ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanging(propertyName);
}
protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
}
//-------------------------------------------------------------------
protected override void OnAdded (View view)
{
base.OnAdded(view);
}
protected override void OnChildAdded (Element child)
{
base.OnChildAdded(child);
}
//-------------------------------------------------------------------
protected override void OnRemoved (View view)
{
base.OnRemoved(view);
}
protected override void OnChildRemoved (Element child)
{
base.OnChildRemoved(child);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Layouts
{
//=======================================================================
public class SaxStackLayout : StackLayout
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxStackLayout ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Layouts
{
//=======================================================================
/// <summary>
/// Wrapping columnar layout - to achieve resposive behaviour.
/// <para>Layout which performs wrapping on the boundaries.</para>
/// <para>Base Code -> https://forums.xamarin.com/discussion/comment/57486/#Comment_57486</para>
/// <para> http://bit.ly/xf-custompanel</para>
/// </summary>
//=======================================================================
public class SaxWrapLayout : Layout<View>
{
//-------------------------------------------------------------------
/// <summary>Horizontal spacing between elements.</summary>
public double SpacingX
{
get { return (double)GetValue(SpacingXProperty); }
set { SetValue(SpacingXProperty, value); }
}
public static BindableProperty SpacingXProperty =
BindableProperty.Create(
nameof(SpacingX),
typeof(double),
typeof(SaxWrapLayout),
default(double),
defaultBindingMode: BindingMode.OneWay,
propertyChanged: (bindable, oldvalue, newvalue) => ((SaxWrapLayout)bindable).InvalidateMeasure()
);
/// <summary>Vertical spacing between elements.</summary>
public double SpacingY
{
get { return (double)GetValue(SpacingYProperty); }
set { SetValue(SpacingYProperty, value); }
}
public static BindableProperty SpacingYProperty =
BindableProperty.Create(
nameof(SpacingY),
typeof(double),
typeof(SaxWrapLayout),
default(double),
defaultBindingMode: BindingMode.OneWay,
propertyChanged: (bindable, oldvalue, newvalue) => ((SaxWrapLayout)bindable).InvalidateMeasure()
);
//-------------------------------------------------------------------
/// <summary>Number of uniform columns in each row.</summary>
public int UniformColumns
{
get { return (int)GetValue(UniformColumnsProperty); }
set { SetValue(UniformColumnsProperty, value); }
}
public static BindableProperty UniformColumnsProperty =
BindableProperty.Create(
nameof(UniformColumns),
typeof(int),
typeof(SaxWrapLayout),
default(int),
defaultBindingMode: BindingMode.OneWay,
propertyChanged: (bindable, oldvalue, newvalue) => ((SaxWrapLayout)bindable).InvalidateMeasure()
);
//-------------------------------------------------------------------
/// <summary>Item height equals item width when UniformColums > 0</summary>
public bool IsSquare
{
get { return (bool)GetValue(IsSquareProperty); }
set { SetValue(IsSquareProperty, value); }
}
public static BindableProperty IsSquareProperty =
BindableProperty.Create(
nameof(IsSquare),
typeof(bool),
typeof(SaxWrapLayout),
false,
propertyChanged: (bindable, oldvalue, newvalue) => ((SaxWrapLayout)bindable).InvalidateMeasure()
);
//-------------------------------------------------------------------
protected override SizeRequest OnMeasure (double widthConstraint, double heightConstraint)
{
if (WidthRequest > 0)
widthConstraint = Math.Min(widthConstraint, WidthRequest);
if (HeightRequest > 0)
heightConstraint = Math.Min(heightConstraint, HeightRequest);
double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint);
double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);
if (double.IsPositiveInfinity(widthConstraint) && double.IsPositiveInfinity(heightConstraint))
{
return new SizeRequest(Size.Zero, Size.Zero);
}
return UniformColumns > 0 ? UniformMeasureAndLayout(internalWidth, internalHeight) :
VariableMeasureAndLayout(internalWidth, internalHeight);
}
//-------------------------------------------------------------------
protected override void LayoutChildren (double x, double y, double width, double height)
{
if (UniformColumns > 0)
UniformMeasureAndLayout(width, height, true, x, y);
else
VariableMeasureAndLayout(width, height, true, x, y);
}
//-------------------------------------------------------------------
private SizeRequest UniformMeasureAndLayout
(double widthConstraint, double heightConstraint, bool doLayout = false, double x = 0, double y = 0)
{
double totalWidth = 0;
double totalHeight = 0;
double rowHeight = 0;
double minWidth = 0;
double minHeight = 0;
double xPos = x;
double yPos = y;
totalWidth = widthConstraint;
var exceptedWidth = widthConstraint - (UniformColumns - 1) * SpacingX; //excepted spacing width
var columnsSize = exceptedWidth / UniformColumns;
if (columnsSize < 1)
{
columnsSize = 1;
}
foreach (var child in Children.Where(c => c.IsVisible))
{
var size = child.Measure(widthConstraint, heightConstraint);
var itemWidth = (double)columnsSize;
var itemHeight = size.Request.Height;
if (IsSquare)
{
itemHeight = columnsSize;
}
rowHeight = Math.Max(rowHeight, itemHeight + SpacingY);
minHeight = Math.Max(minHeight, itemHeight);
minWidth = Math.Max(minWidth, itemWidth);
if (doLayout)
{
var region = new Rectangle(xPos, yPos, itemWidth, itemHeight);
LayoutChildIntoBoundingRegion(child, region);
}
xPos += itemWidth + SpacingX;
if (xPos + columnsSize - x > widthConstraint)
{
xPos = x;
yPos += rowHeight;
totalHeight += rowHeight;
rowHeight = 0;
}
}
totalHeight = Math.Max(totalHeight + rowHeight - SpacingY, 0);
return new SizeRequest(new Size(totalWidth, totalHeight), new Size(minWidth, minHeight));
}
//-------------------------------------------------------------------
private SizeRequest VariableMeasureAndLayout
(double widthConstraint, double heightConstraint, bool doLayout = false, double x = 0, double y = 0)
{
double totalWidth = 0;
double totalHeight = 0;
double rowHeight = 0;
double rowWidth = 0;
double minWidth = 0;
double minHeight = 0;
double xPos = x;
double yPos = y;
var visibleChildren = Children.Where(c => c.IsVisible).Select(c => new
{
child = c,
size = c.Measure(widthConstraint, heightConstraint)
});
var nextChildren = visibleChildren.Skip(1).ToList();
nextChildren.Add(null); //make element count same
var zipChildren = visibleChildren.Zip(nextChildren, (c, n) => new { current = c, next = n });
foreach (var childBlock in zipChildren)
{
var child = childBlock.current.child;
var size = childBlock.current.size;
var itemWidth = size.Request.Width;
var itemHeight = size.Request.Height;
rowHeight = Math.Max(rowHeight, itemHeight + SpacingY);
rowWidth += itemWidth + SpacingX;
minHeight = Math.Max(minHeight, itemHeight);
minWidth = Math.Max(minWidth, itemWidth);
if (doLayout)
{
var region = new Rectangle(xPos, yPos, itemWidth, itemHeight);
LayoutChildIntoBoundingRegion(child, region);
}
if (childBlock.next == null)
{
totalHeight += rowHeight;
totalWidth = Math.Max(totalWidth, rowWidth);
break;
}
xPos += itemWidth + SpacingX;
var nextWitdh = childBlock.next.size.Request.Width;
if (xPos + nextWitdh - x > widthConstraint)
{
xPos = x;
yPos += rowHeight;
totalHeight += rowHeight;
totalWidth = Math.Max(totalWidth, rowWidth);
rowHeight = 0;
rowWidth = 0;
}
}
totalWidth = Math.Max(totalWidth - SpacingX, 0);
totalHeight = Math.Max(totalHeight - SpacingY, 0);
return new SizeRequest(new Size(totalWidth, totalHeight), new Size(minWidth, minHeight));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,92 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Pages
{
//=======================================================================
public abstract class SaxContentPage : ContentPage
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
protected SaxContentPage ()
{
}
//-------------------------------------------------------------------
// Properties.
public abstract String MessageTitleDefault { get; }
//-------------------------------------------------------------------
// P o p u p M e s s a g e s
//-------------------------------------------------------------------
public enum AlertMode
{
OK,
Close,
}
public Task DisplayAlert (String message, AlertMode alertMode = AlertMode.OK)
{
String title = StringUtil.OnEmpty(Title, MessageTitleDefault);
String cancel = "OK";
if (alertMode == AlertMode.Close)
cancel = "Close";
return DisplayAlert(title, message, cancel);
}
public enum ConfirmMode
{
YesNo,
OkCancel
}
public async Task<bool> DisplayConfirm (String message, ConfirmMode confirmMode = ConfirmMode.OkCancel)
{
String title = StringUtil.OnEmpty(Title, MessageTitleDefault);
String accept = "Yes";
String cancel = "No";
if (confirmMode == ConfirmMode.OkCancel)
{
accept = "OK";
cancel = "Cancel";
}
return await DisplayAlert(title, message, accept, cancel);
}
//-------------------------------------------------------------------
// P a g e E v e n t s
//-------------------------------------------------------------------
protected override void OnParentSet ()
{
base.OnParentSet();
}
//-------------------------------------------------------------------
protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
}
//-------------------------------------------------------------------
protected override void OnAppearing ()
{
base.OnAppearing();
}
//-------------------------------------------------------------------
protected override void OnDisappearing ()
{
base.OnDisappearing();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,82 @@
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxPanel ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// C o n f i g u r e C o m p o n e n t s
//-------------------------------------------------------------------
protected override void ConfigureComponents ()
{
base.ConfigureComponents();
}
//-------------------------------------------------------------------
// C o n t r o l A c t i v i t y
//-------------------------------------------------------------------
protected override void SetControlActivity ()
{
}
protected override void SetControlsReadOnly ()
{
}
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
protected override void OnParentSet ()
{
base.OnParentSet();
}
//-------------------------------------------------------------------
protected override void OnPropertyChanging ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanging(propertyName);
}
protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
}
//-------------------------------------------------------------------
protected override void OnChildAdded (Element child)
{
base.OnChildAdded(child);
}
protected override void OnChildRemoved (Element child)
{
base.OnChildRemoved(child);
}
//-------------------------------------------------------------------
protected override void OnSizeAllocated (double width, double height)
{
base.OnSizeAllocated(width, height);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,170 @@
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Templates;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SacsFilterPropertyType
{
public enum FilterMode { Text, DropDownList }
public SacsFilterPropertyType (int propertyType, String caption)
{
PropertyType = propertyType;
Caption = caption;
}
public int PropertyType { get; }
public String Caption { get; }
public FilterMode Mode { get; set; } = FilterMode.Text;
}
public class SaxPanel_ItemFilter : SaxWrapLayout
{
//-------------------------------------------------------------------
// Definitions.
public class Config
{
public List<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
public ushort FiltersToDisplay { get; set; } = 2;
public int PropertyTypeWidth { get; set; } = 100;
public int PropertyValueWidth { get; set; } = 120;
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private SaxPanel_ItemFilterProperty[] itemFilterProperties = new SaxPanel_ItemFilterProperty[0];
//-------------------------------------------------------------------
// Construction.
public SaxPanel_ItemFilter (Config config)
{
this.config = config;
InitialiseComponents();
}
//-------------------------------------------------------------------
// Properties.
public int FilterCount { get { return Math.Min(config.FiltersToDisplay, config.FilterPropertyTypes.Count); } }
//-------------------------------------------------------------------
// Configure.
public void SetConfig (Config config)
{
this.config = config;
ConfigurePanel();
}
//-------------------------------------------------------------------
// P u b l i c I n t e r f a c e
//-------------------------------------------------------------------
public String GetFilterPropertyValue (int propertyType)
{
foreach (SaxPanel_ItemFilterProperty propertyFilter in itemFilterProperties)
{
if (propertyFilter.SelectedPropertyType == propertyType)
return propertyFilter.PropertyValue;
}
return "";
}
//-------------------------------------------------------------------
// I n i t i a l i s e
//-------------------------------------------------------------------
private void InitialiseComponents ()
{
// Styling.
SpacingX = 8.0;
SpacingY = 4.0;
BackgroundColor = Color.Transparent;
ConfigurePanel();
}
//-------------------------------------------------------------------
// C o n f i g u r e P a n e l
//-------------------------------------------------------------------
private void ConfigurePanel ()
{
// Clear filter panels.
Children.Clear();
// Reconfigure fiter properties.
if (itemFilterProperties.Length != FilterCount)
{
// Create new set of filters and copy previous filters across up to required number.
SaxPanel_ItemFilterProperty [] itemFilterPropertiesNew = new SaxPanel_ItemFilterProperty[FilterCount];
for (int filterIdx = 0; filterIdx < Math.Min(itemFilterProperties.Length, FilterCount); filterIdx++)
itemFilterPropertiesNew[filterIdx] = itemFilterProperties[filterIdx];
for (int filterIdx = itemFilterProperties.Length; filterIdx < FilterCount; filterIdx++)
{
itemFilterPropertiesNew[filterIdx] = new SaxPanel_ItemFilterProperty(new SaxPanel_ItemFilterProperty.Config());
itemFilterPropertiesNew[filterIdx].PropertyFilterChanged += SaxPanel_ItemFilter_PropertyFilterChanged;
}
itemFilterProperties = itemFilterPropertiesNew;
}
// Retrieve currently selected property types.
List<int> selectedPropertyTypes = new List<int>();
for (int filterIdx = 0; filterIdx < FilterCount; filterIdx++)
{
int selectedPropertyType = itemFilterProperties[filterIdx].SelectedPropertyType;
if (selectedPropertyType >= 0 && !selectedPropertyTypes.Contains(selectedPropertyType))
selectedPropertyTypes.Add(selectedPropertyType);
}
// Configure filter panels.
for (int filterIdx = 0; filterIdx < FilterCount; filterIdx++)
{
SaxPanel_ItemFilterProperty propertyPanel = itemFilterProperties[filterIdx];
// Determine the property types to display - remove property types selected in other panels.
List<SacsFilterPropertyType> filterPropertyTypes = new List<SacsFilterPropertyType>(config.FilterPropertyTypes);
filterPropertyTypes.RemoveAll(item => item.PropertyType != propertyPanel.SelectedPropertyType && selectedPropertyTypes.Contains(item.PropertyType));
if (filterPropertyTypes.Count == 0) continue;
SaxPanel_ItemFilterProperty.Config propertyPanelConfig = new SaxPanel_ItemFilterProperty.Config();
propertyPanelConfig.FilterPropertyTypes.AddRange(filterPropertyTypes);
propertyPanelConfig.PropertyTypeWidth = config.PropertyTypeWidth;
propertyPanelConfig.PropertyValueWidth = config.PropertyValueWidth;
propertyPanel.SetConfig(propertyPanelConfig);
// Include the selecetd type in the list of not already present.
int selectedPropertyType = propertyPanel.SelectedPropertyType;
if (selectedPropertyType >= 0 && !selectedPropertyTypes.Contains(selectedPropertyType))
selectedPropertyTypes.Add(selectedPropertyType);
// Add panel to the layout.
Children.Add(propertyPanel);
}
}
//-------------------------------------------------------------------
// F i l t e r E v e n t s
//-------------------------------------------------------------------
public class FilterChangedEventArgs : EventArgs
{
public int PropertyType { get; set; } = -1;
}
public event EventHandler<FilterChangedEventArgs> FilterChanged;
private void FireFilterChangedEvent (int propertyType)
{
FilterChangedEventArgs filterChangedEventArgs = new FilterChangedEventArgs()
{
PropertyType = propertyType,
};
if (FilterChanged != null) FilterChanged.Invoke(this, filterChangedEventArgs);
}
//-------------------------------------------------------------------
private void SaxPanel_ItemFilter_PropertyFilterChanged (object sender, SaxPanel_ItemFilterProperty.PropertyFilterChangedEventArgs e)
{
FireFilterChangedEvent(e.PropertyType);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,171 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Templates;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel_ItemFilterProperty : SaxPanel
{
//-------------------------------------------------------------------
// Definitions.
public class Config
{
public List<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
public GridLength Height { get; set; } = GridLength.Auto;
public int PropertyTypeWidth { get; set; } = 0;
public int PropertyValueWidth { get; set; } = 0;
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private SaxGrid grid;
private SaxPicker pickerPropertyType = new SaxPicker();
private SaxEntry entryPropertyValue = new SaxEntry() { Text = "", HorizontalOptions = LayoutOptions.FillAndExpand };
private SaxPicker pickerPropertyValue = new SaxPicker(){ HorizontalOptions = LayoutOptions.FillAndExpand , IsVisible = false };
//-------------------------------------------------------------------
// Construction.
public SaxPanel_ItemFilterProperty (Config config)
{
this.config = config;
InitialiseComponents();
}
//-------------------------------------------------------------------
// Properties.
public bool Initialising { get; set; } = true;
private SacsFilterPropertyType SelectedProperty { get { return config.FilterPropertyTypes.Find(item => item.PropertyType == StringUtil.ToInt(pickerPropertyType.SelectedItemCode)); } }
public int SelectedPropertyType { get { return SelectedProperty?.PropertyType ?? -1; } }
public String PropertyValue
{
get
{
if (SelectedProperty.Mode == SacsFilterPropertyType.FilterMode.DropDownList)
return pickerPropertyValue.SelectedItemCode;
return entryPropertyValue.Text;
}
}
//-------------------------------------------------------------------
// Configure.
public void SetConfig (Config config)
{
this.config = config;
ConfigurePanel();
}
//-------------------------------------------------------------------
// I n i t i a l i s e
//-------------------------------------------------------------------
private void InitialiseComponents ()
{
// Grid - property type picker followed by property value control.
grid = new SaxGrid()
{
BackgroundColor = Color.Transparent,
RowSpacing = 0,
ColumnSpacing = 4,
RowDefinitions = new RowDefinitionCollection()
{
// Single row.
new RowDefinition(){ Height = config.Height }
},
ColumnDefinitions = new ColumnDefinitionCollection()
{
// Two columns - property type & value.
new ColumnDefinition(){ Width = config.PropertyTypeWidth > 0 ? config.PropertyTypeWidth : GridLength.Auto },
new ColumnDefinition(){ Width = config.PropertyValueWidth > 0 ? config.PropertyValueWidth : GridLength.Auto }
}
};
Content = grid;
// Property type.
if (config.PropertyTypeWidth > 0)
pickerPropertyType.WidthRequest = config.PropertyTypeWidth;
grid.Children.Add(pickerPropertyType, 0, 0);
pickerPropertyType.SelectedIndexChanged += PickerPropertyType_SelectedIndexChanged;
// Property value.
if (config.PropertyValueWidth > 0)
entryPropertyValue.WidthRequest = config.PropertyValueWidth;
entryPropertyValue.TextChanged += EntryPropertyValue_TextChanged;
grid.Children.Add(entryPropertyValue, 1, 0);
if (config.PropertyValueWidth > 0)
pickerPropertyValue.WidthRequest = config.PropertyValueWidth;
pickerPropertyValue.SelectedIndexChanged += PickerPropertyValue_SelectedIndexChanged;
grid.Children.Add(pickerPropertyValue, 1, 0);
ConfigurePanel();
}
//-------------------------------------------------------------------
// C o n f i g u r e P a n e l
//-------------------------------------------------------------------
private void ConfigurePanel ()
{
Initialising = true;
// Configure layout.
grid.ColumnDefinitions.Clear();
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = config.PropertyTypeWidth });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = config.PropertyValueWidth });
// Make a note of the currently selected property type.
int selectedPropertyType = SelectedPropertyType;
pickerPropertyType.ClearItems();
// Populate list of property types.
foreach (SacsFilterPropertyType propertyType in config.FilterPropertyTypes)
{
pickerPropertyType.AddItem(propertyType.PropertyType.ToString(), propertyType.Caption);
}
pickerPropertyType.SelectedItemCode = selectedPropertyType.ToString();
if (pickerPropertyType.SelectedIndex < 0 && pickerPropertyType.Items.Count > 0)
pickerPropertyType.SelectedIndex = 0;
Initialising = false;
}
//-------------------------------------------------------------------
// P r o p e r t y F i l t e r E v e n t s
//-------------------------------------------------------------------
public class PropertyFilterChangedEventArgs : EventArgs
{
public int PropertyType { get; set; } = -1;
}
public event EventHandler<PropertyFilterChangedEventArgs> PropertyFilterChanged;
private void FireFilterChangedEvent (int propertyType)
{
if (Initialising) return;
PropertyFilterChangedEventArgs filterChangedEventArgs = new PropertyFilterChangedEventArgs()
{
PropertyType = propertyType,
};
if (PropertyFilterChanged != null) PropertyFilterChanged.Invoke(this, filterChangedEventArgs);
}
//-------------------------------------------------------------------
private void PickerPropertyType_SelectedIndexChanged (object sender, EventArgs e)
{
FireFilterChangedEvent(SelectedPropertyType);
}
private void EntryPropertyValue_TextChanged (object sender, TextChangedEventArgs e)
{
FireFilterChangedEvent(SelectedPropertyType);
}
private void PickerPropertyValue_SelectedIndexChanged (object sender, EventArgs e)
{
FireFilterChangedEvent(SelectedPropertyType);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,286 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Views;
using Sarand.Net.Standard.Mobile.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel_ItemListHeader : SaxPanel
{
//-------------------------------------------------------------------
// Definitions.
public class Config
{
public Thickness Margin { get; set; } = new Thickness(0, 0, 0, 8);
public String Caption { get; set; }
public double HeaderBorderWidth { get; set; } = 4.0;
public float HeaderBorderRadius { get; set; } = 8.0f;
public Color HeaderBorderColor { get; set; } = Color.FromHex("#808080");
public Color HeaderBackgroundColor { get; set; } = Color.FromHex("#F0F0F0");
// Labels.
// Styling.
public double CaptionLabelFontSizeRatio { get; set; } = 1.0;
public double PagingLabelFontSizeRatio { get; set; } = 1.0;
public Thickness LabelMargin { get; set; }
// Paging controls.
public static int PagingButtonWidthMin { get; } = 40;
public static int PagingButtonWidthMax { get; } = 64;
public static int PagingButtonWidthDefault { get; } = PagingButtonWidthMin;
public int PagingButtonWidth { get; set; } = PagingButtonWidthDefault;
public static int PagingButtonHeightMin { get; } = 40;
public static int PagingButtonHeightMax { get; } = 64;
public static int PagingButtonHeightDefault { get; } = PagingButtonHeightMin;
public int PagingButtonHeight { get; set; } = PagingButtonHeightDefault;
// Filters.
public List<SacsFilterPropertyType> FilterPropertyTypes { get; } = new List<SacsFilterPropertyType>();
public ushort FiltersToDisplay { get; set; } = 2;
}
//-------------------------------------------------------------------
// Data members.
private Config config;
// Layout.
private SaxFrame frame = new SaxFrame();
private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation=StackOrientation.Vertical };
// Header.
private SaxWrapLayout headerLayout = new SaxWrapLayout() { SpacingX = 8.0 };
private SaxContentView captionLabelView = new SaxContentView();
private SaxLabel labelCaption = new SaxLabel() { Text = "" };
private double initialLabelFontSize = 0;
// Paging.
private class PagingData : DbQuery.Paging
{
public int TotalItems { get; set; }
public int TotalPages { get { return PageLength > 0 ? (int)Math.Ceiling((double)TotalItems / PageLength) : 0; } }
public override bool Paged { get { return base.Paged && TotalItems > 0; } }
}
private readonly PagingData paging = new PagingData();
private SaxStackLayout pagingStack = new SaxStackLayout() { Orientation=StackOrientation.Horizontal };
private SaxLabel labelPaging = new SaxLabel() { Text = "[Paging]" };
private SaxImageButton buttonPagingFirst = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent };
private SaxImageButton buttonPagingPrev = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent };
private SaxImageButton buttonPagingNext = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent };
private SaxImageButton buttonPagingLast = new SaxImageButton() { WidthRequest = 32, HeightRequest = 32, Aspect = Aspect.AspectFit, Padding = new Thickness(2,4), BackgroundColor = Color.Transparent };
//-------------------------------------------------------------------
// Construction.
public SaxPanel_ItemListHeader (Config config)
{
this.config = config;
initialLabelFontSize = labelCaption.FontSize;
InitialiseComponents();
}
//-------------------------------------------------------------------
// Properties.
// Filter.
public SaxPanel_ItemFilter PanelFilter { get; private set; }
// Paging.
public uint PageNo { get { return paging.PageNo; } }
public ushort PageLength { get { return paging.PageLength; } }
public int TotalItems { get { return paging.TotalItems; } }
//-------------------------------------------------------------------
// I n i t i a l i s e
//-------------------------------------------------------------------
private void InitialiseComponents ()
{
// Frame - to allow rounded corners.
Content = frame;
frame.Content = mainLayout;
// Header.
mainLayout.Spacing = 0;
mainLayout.HorizontalOptions = LayoutOptions.StartAndExpand;
mainLayout.BackgroundColor = Color.Transparent;
//headerLayout.BackgroundColor = Color.LightYellow;
mainLayout.Children.Add(headerLayout);
// Header - Caption.
captionLabelView.VerticalOptions = LayoutOptions.Center;
labelCaption.FontAttributes = FontAttributes.Bold;
labelCaption.HorizontalOptions = LayoutOptions.StartAndExpand;
labelCaption.VerticalOptions = LayoutOptions.CenterAndExpand;
labelCaption.LineBreakMode = LineBreakMode.NoWrap;
labelCaption.PropertyChanging += LabelCaption_PropertyChanging;
// Label is embedded in view to ensure correct sizing.
captionLabelView.Content = labelCaption;
headerLayout.Children.Add(captionLabelView);
// Header - Paging.
pagingStack.HorizontalOptions = LayoutOptions.EndAndExpand;
pagingStack.VerticalOptions = LayoutOptions.CenterAndExpand;
headerLayout.Children.Add(pagingStack);
labelPaging.VerticalOptions = LayoutOptions.CenterAndExpand;
pagingStack.Children.Add(labelPaging);
pagingStack.Children.Add(buttonPagingFirst);
pagingStack.Children.Add(buttonPagingPrev);
pagingStack.Children.Add(buttonPagingNext);
pagingStack.Children.Add(buttonPagingLast);
// Paging actions.
buttonPagingFirst.Clicked += ButtonPagingFirst_Clicked;
buttonPagingPrev.Clicked += ButtonPagingPrev_Clicked;
buttonPagingNext.Clicked += ButtonPagingNext_Clicked;
buttonPagingLast.Clicked += ButtonPagingLast_Clicked;
// Complete panel configuration.
ConfigurePanel();
}
private void LabelCaption_PropertyChanging (object sender, PropertyChangingEventArgs e)
{
if (e.PropertyName.EqualsCI("Height"))
{
}
}
//-------------------------------------------------------------------
// C o n f i g u r e P a n e l
//-------------------------------------------------------------------
private void ConfigurePanel ()
{
frame.Margin = config.Margin;
// Header.
labelCaption.Text = StringUtil.EmptyOnNull(config.Caption);
frame.Padding = new Thickness(config.HeaderBorderWidth);
frame.CornerRadius = config.HeaderBorderRadius;
frame.BorderColor = config.HeaderBorderColor;
frame.BackgroundColor = config.HeaderBackgroundColor;
// Labels.
labelCaption.FontSize = initialLabelFontSize * config.CaptionLabelFontSizeRatio;
labelPaging.FontSize = initialLabelFontSize * config.PagingLabelFontSizeRatio;
if (config.LabelMargin != null)
{
labelCaption.Margin = config.LabelMargin;
labelPaging.Margin = config.LabelMargin;
}
// Paging controls.
buttonPagingFirst.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Left_Double_Black_24_png));
buttonPagingFirst.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth));
buttonPagingFirst.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight));
buttonPagingPrev.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Left_Black_24_png));
buttonPagingPrev.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth));
buttonPagingPrev.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight));
buttonPagingNext.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Right_Black_24_png));
buttonPagingNext.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth));
buttonPagingNext.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight));
buttonPagingLast.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.Arrow_Right_Double_Black_24_png));
buttonPagingLast.WidthRequest = Math.Max(Config.PagingButtonWidthMin, Math.Min(Config.PagingButtonWidthMax, config.PagingButtonWidth));
buttonPagingLast.HeightRequest = Math.Max(Config.PagingButtonHeightMin, Math.Min(Config.PagingButtonHeightMax, config.PagingButtonHeight));
RefreshPaging();
// Property type filters.
SaxPanel_ItemFilter.Config propertyFilterConfig = new SaxPanel_ItemFilter.Config();
propertyFilterConfig.FilterPropertyTypes.AddRange(config.FilterPropertyTypes);
propertyFilterConfig.FiltersToDisplay = config.FiltersToDisplay;
if (PanelFilter == null)
{
PanelFilter = new SaxPanel_ItemFilter(propertyFilterConfig);
mainLayout.Children.Add(PanelFilter);
}
else
{
PanelFilter.SetConfig(propertyFilterConfig);
}
}
//-------------------------------------------------------------------
// P a g i n g
//-------------------------------------------------------------------
public void SetPaging (uint pageNo, ushort pageLength, int totalItems)
{
paging.PageNo = pageNo;
paging.PageLength = pageLength;
paging.TotalItems = totalItems;
RefreshPaging();
}
private void RefreshPaging ()
{
String pagingText = "";
Boolean paged = (paging.Paged && paging.TotalPages > 1);
if (paging.TotalItems > 0)
{
if (paged)
pagingText = "Page " + paging.PageNo + " of " + paging.TotalPages;
else
pagingText = paging.TotalItems + " items";
}
labelPaging.Text = pagingText;
// Control visibility.
labelPaging.IsVisible = !StringUtil.IsEmpty(labelPaging.Text);
buttonPagingFirst.IsVisible = paged;
buttonPagingPrev.IsVisible = paged;
buttonPagingNext.IsVisible = paged;
buttonPagingLast.IsVisible = paged;
// Button activity.
buttonPagingFirst.IsEnabled = paging.PageNo > 1;
buttonPagingPrev.IsEnabled = paging.PageNo > 1;
buttonPagingNext.IsEnabled = paging.PageNo < paging.TotalPages;
buttonPagingLast.IsEnabled = paging.PageNo < paging.TotalPages;
}
//-------------------------------------------------------------------
// Paging events.
public enum PagingActionType
{
Unknown,
First,
Next,
Prev,
Last
}
public class PagingActionEventArgs : EventArgs
{
public PagingActionType PagingActionType { get; set; } = PagingActionType.Unknown;
}
public event EventHandler<PagingActionEventArgs> PagingAction;
private void FirePagingActionEvent (PagingActionType pagingActionType)
{
PagingActionEventArgs filterChangedEventArgs = new PagingActionEventArgs()
{
PagingActionType = pagingActionType,
};
if (PagingAction != null) PagingAction.Invoke(this, filterChangedEventArgs);
}
//-------------------------------------------------------------------
// Paging actions.
private void ButtonPagingFirst_Clicked (object sender, EventArgs e)
{
FirePagingActionEvent(PagingActionType.First);
}
private void ButtonPagingPrev_Clicked (object sender, EventArgs e)
{
FirePagingActionEvent(PagingActionType.Prev);
}
private void ButtonPagingNext_Clicked (object sender, EventArgs e)
{
FirePagingActionEvent(PagingActionType.Next);
}
private void ButtonPagingLast_Clicked (object sender, EventArgs e)
{
FirePagingActionEvent(PagingActionType.Last);
}
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,128 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using Sarand.Net.Standard.Mobile.Forms.Views;
using Sarand.Net.Standard.Mobile.Utils;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
/// <summary>
/// Panel to display with item list where no filter required, eg. items associated with parent.
/// <para>- Message shown to left</para>
/// <para>- Buttons shown to right</para>
/// </summary>
public class SaxPanel_ItemListSummary : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private SacsMessage message;
private bool showAddButton = false;
private double actionButtonSpacing = 4.0;
// Panel layout.
private SaxStackLayout panelLayout = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal };
private SaxContentView panelMessage = new SaxContentView();
private SaxLabel labelMessage = new SaxLabel() { HorizontalOptions = LayoutOptions.Start};
// Action butons.
private SaxStackLayout panelActions = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Horizontal };
private SaxImageButton buttonAddItem = new SaxImageButton() { IsVisible = false, HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Start };
//-------------------------------------------------------------------
// Construction.
public SaxPanel_ItemListSummary ()
{
// Panel layout.
panelLayout.HorizontalOptions = LayoutOptions.Fill;
Content = panelLayout;
// Message.
panelMessage.HorizontalOptions = LayoutOptions.Fill;
panelMessage.VerticalOptions = LayoutOptions.Fill;
//panelMessage.BackgroundColor = Color.LightGoldenrodYellow;
panelLayout.Children.Add(panelMessage);
labelMessage.HorizontalOptions = LayoutOptions.Center;
labelMessage.VerticalOptions = LayoutOptions.Center;
panelMessage.Content = labelMessage;
// Action buttons.
panelActions.HorizontalOptions = LayoutOptions.EndAndExpand;
panelLayout.Children.Add(panelActions);
// 'Add' button.
buttonAddItem.IsVisible = showAddButton;
buttonAddItem.Padding = new Thickness(0, 0, actionButtonSpacing, 0);
buttonAddItem.BackgroundColor = Color.Transparent;
buttonAddItem.Source = SacsImageUtils.GetImageFromByteArray(SacsResourceHelper.GetImageResource(SacsResourceHelper.ImageResource.IconShock_Add_Green_72_png));
buttonAddItem.Clicked += ButtonAddItem_Clicked;
panelActions.Children.Add(buttonAddItem);
}
//-------------------------------------------------------------------
// Properties.
// Message.
public double DefaultMessageFontSize { get { return labelMessage.DefaultFontSize; } }
public double MessageFontSize
{
get { return labelMessage.FontSize; }
set { labelMessage.FontSize = value; }
}
// Action buttons.
public double ActionButtonSpacing
{
get { return actionButtonSpacing; }
set
{
if (actionButtonSpacing == value) return;
buttonAddItem.Padding = new Thickness(0, 0, actionButtonSpacing, 0);
}
}
public bool ShowAddButton
{
get { return showAddButton; }
set { if (showAddButton == value) return; showAddButton = value; buttonAddItem.IsVisible = showAddButton; }
}
//-------------------------------------------------------------------
// M e s s a g e
//-------------------------------------------------------------------
public void ClearMessage ()
{
message = null;
labelMessage.Text = "";
}
public void SetMessage (String message, SaMessageLevel messageLevel = SaMessageLevel.Info)
{
SetMessage(new SacsMessage(message, messageLevel));
}
public void SetMessage (SacsMessage message)
{
this.message = message;
labelMessage.Text = (message != null ? message.Message : "");
}
//-------------------------------------------------------------------
// A c t i o n B u t t o n s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
public event EventHandler<EventArgs> AddClicked;
protected virtual void ButtonAddItem_Clicked (object sender, EventArgs e)
{
if (AddClicked != null) AddClicked.Invoke(sender, e);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,75 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Layouts;
using System;
using System.Collections.Generic;
using System.Text;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel_Messages : SaxPanel
{
//-------------------------------------------------------------------
// Definitions.
public class Config
{
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private readonly List<SacsMessage> messages = new List<SacsMessage>();
// Components.
private SaxStackLayout mainLayout = new SaxStackLayout() { Orientation = Xamarin.Forms.StackOrientation.Vertical };
//-------------------------------------------------------------------
// Construction.
public SaxPanel_Messages (Config config)
{
this.config = config;
Content = mainLayout;
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// M e s s a g e s
//-------------------------------------------------------------------
public void ClearMessages ()
{
messages.Clear();
RefreshLayout();
}
public void AddMessage (SacsMessage message)
{
messages.Add(message);
RefreshLayout();
}
//-------------------------------------------------------------------
// R e f r e s h L a y o u t
//-------------------------------------------------------------------
private void RefreshLayout()
{
// Reset layout.
IsVisible = messages.Count > 0;
mainLayout.Children.Clear();
foreach (SacsMessage message in messages)
{
SaxPanel messagePanel = new SaxPanel();
messagePanel.Content = new SaxLabel() { Text = message.Message };
mainLayout.Children.Add(messagePanel);
}
}
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,93 @@
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Templates;
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel_Progress : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
public class Config
{
}
//-------------------------------------------------------------------
// Data members.
private Config config;
// Panel layout.
private SaxGrid gridPanel = new SaxGrid();
private SaxContentView viewPanel = new SaxContentView();
private SaxLabel labelProgressMessage = new SaxLabel();
//-------------------------------------------------------------------
// Construction.
public SaxPanel_Progress (Config config)
{
this.config = config;
InitialiseComponents();
}
//-------------------------------------------------------------------
// Properties.
public double ProgressMessageDefaultFontSize { get { return labelProgressMessage.DefaultFontSize; } }
public double ProgressMessageFontSize { get { return labelProgressMessage.FontSize; } set { labelProgressMessage.FontSize = value; } }
public FontAttributes ProgressMessageFontAttributes { get { return labelProgressMessage.FontAttributes; } set { labelProgressMessage.FontAttributes = value; } }
public Color ProgressMessageColor { get { return labelProgressMessage.TextColor; } set { labelProgressMessage.TextColor = value; } }
public String ProgressMessage { get { return labelProgressMessage.Text; } set { labelProgressMessage.Text = value; } }
public Thickness ProgressMessagePadding { get { return viewPanel.Padding; } set { viewPanel.Padding = value; } }
public Color ProgressMessageBackgroundColor { get { return viewPanel.BackgroundColor; } set { viewPanel.BackgroundColor = value; } }
//-------------------------------------------------------------------
// I n i t i a l i s e
//-------------------------------------------------------------------
private void InitialiseComponents ()
{
// Layout is a 3x3 grid with only the central cell populated.
// All other cells are transparent/opaque.
gridPanel.BackgroundColor = new Color(0, 0, 0, 0.5);
gridPanel.HorizontalOptions = LayoutOptions.FillAndExpand;
gridPanel.VerticalOptions = LayoutOptions.FillAndExpand;
gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
gridPanel.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star });
gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
gridPanel.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star });
Content = gridPanel;
// The panel's view.
viewPanel.Padding = new Thickness(12.0);
viewPanel.BackgroundColor = Color.WhiteSmoke;
viewPanel.HorizontalOptions = LayoutOptions.Center;
viewPanel.VerticalOptions = LayoutOptions.Center;
gridPanel.Children.Add(viewPanel, 1, 1);
// Progress message.
viewPanel.Content = labelProgressMessage;
// Complete panel configuration.
ConfigurePanel();
}
//-------------------------------------------------------------------
// C o n f i g u r e P a n e l
//-------------------------------------------------------------------
private void ConfigurePanel ()
{
// Panel initialisation that depends on the configuration.
}
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,140 @@
using Sarand.Net.Standard.Mobile.Forms.Controls;
using Sarand.Net.Standard.Mobile.Forms.Templates;
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxPanel_PropertySummary : SaxContentView
{
//-------------------------------------------------------------------
// Definitions.
private class PropertyData
{
public String Caption { get; set; }
public String Value { get; set; }
}
//-------------------------------------------------------------------
// Data members.
private float internalFrameRadiusFactor = 0.8f;
private readonly List<PropertyData> properties = new List<PropertyData>();
// Panel components.
private SaxFrame framePanel = new SaxFrame();
private SaxFrame frameInternal = new SaxFrame();
private SaxGrid gridProperties = new SaxGrid();
//-------------------------------------------------------------------
// Construction.
public SaxPanel_PropertySummary ()
{
// View properties.
//BackgroundColor = Color.Transparent;
framePanel.CornerRadius = 8.0f;
framePanel.Padding = new Thickness(2.0);
framePanel.BackgroundColor = Color.Transparent;
framePanel.BorderColor = framePanel.BorderColor;
Content = framePanel;
// Frame.
frameInternal.CornerRadius = framePanel.CornerRadius * internalFrameRadiusFactor;
frameInternal.Padding = new Thickness(0);
frameInternal.BorderColor = Color.White;
frameInternal.BackgroundColor = Color.White;
framePanel.Content = frameInternal;
frameInternal.Content = gridProperties;
// Properties grid.
gridProperties.Padding = new Thickness(4.0);
gridProperties.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
gridProperties.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
// Property styling.
DefaultFontSize = new SaxLabel().FontSize;
FontSize = DefaultFontSize;
ConfigureComponents();
}
//-------------------------------------------------------------------
// Properties.
public Color BorderColor
{
get { return framePanel.BorderColor; }
set
{
framePanel.BorderColor = value;
framePanel.BackgroundColor = value;
}
}
public Thickness BorderWidth { get { return framePanel.Padding; } set { framePanel.Padding = value; } }
public float CornerRadius
{
get { return framePanel.CornerRadius; }
set
{
framePanel.CornerRadius = value;
frameInternal.CornerRadius = framePanel.CornerRadius * internalFrameRadiusFactor;
}
}
public Color PanelBackgroundColor
{
get { return frameInternal.BackgroundColor; }
set
{
frameInternal.BorderColor = value;
frameInternal.BackgroundColor = value;
}
}
// Property label styling.
public double DefaultFontSize { get; }
public double FontSize { get; set; }
//-------------------------------------------------------------------
// S u m m a r y P r o p e r t i e s
//-------------------------------------------------------------------
public void AddProperty (String caption, String value)
{
properties.Add(new PropertyData() { Caption = caption, Value = value });
RefreshProperties();
}
public void ClearProperties ()
{
properties.Clear();
RefreshProperties();
}
private void RefreshProperties ()
{
// Clear existing properties.
gridProperties.Children.Clear();
gridProperties.RowDefinitions.Clear();
foreach (PropertyData property in properties)
{
int rowIdx = gridProperties.RowDefinitions.Count;
gridProperties.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
gridProperties.Children.Add(new SaxLabel() { Text = property.Caption, FontSize = FontSize, HorizontalOptions = LayoutOptions.End }, 0, rowIdx);
gridProperties.Children.Add(new SaxLabel() { Text = property.Value, FontSize = FontSize, HorizontalOptions = LayoutOptions.StartAndExpand, VerticalOptions = LayoutOptions.StartAndExpand }, 1, rowIdx);
}
}
//-------------------------------------------------------------------
// C o n f i g u r e C o m p o n e n t s
//-------------------------------------------------------------------
protected override void ConfigureComponents ()
{
base.ConfigureComponents();
}
//-------------------------------------------------------------------
// P a n e l E v e n t s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,51 @@
using Sarand.Net.Standard.Mobile.Forms.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Panels
{
//=======================================================================
public class SaxTabPanel : SaxPanel
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxTabPanel (String caption, SaxContentView panel)
{
Caption = caption;
// This panel includes border layout around the actual tab panel content.
Padding = new Thickness(2.0);
BackgroundColor = Color.LightSlateGray;
Content = panel;
}
//-------------------------------------------------------------------
// Properties.
public String Caption { get; }
public Thickness BorderWidth
{
get { return Padding; }
set { if (Padding == value) return; Padding = value; }
}
public Color BorderColor
{
get { return BackgroundColor; }
set { if (BackgroundColor == value) return; BackgroundColor = value; }
}
//-------------------------------------------------------------------
// T a b P a n e l s
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,38 @@
using Sarand.Net.Standard.Mobile.Tasks;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Utils
{
//=======================================================================
public static class SaxFormsUtil
{
//-------------------------------------------------------------------
// D i s p l a y A l e r t a n d W a i t
//-------------------------------------------------------------------
public static void DisplayAlertSync (String title, String message, String cancel = "OK")
{
SaxThreadUtil.BeginInvokeOnMainThreadSync(async () => await Application.Current.MainPage.DisplayAlert(title, message, cancel));
}
public static bool DisplayConfirmSync (String title, String message, String accept = "Yes", String cancel = "No")
{
var tcs = new TaskCompletionSource<bool>();
Device.BeginInvokeOnMainThread(async () =>
{
try
{
bool result = await Application.Current.MainPage.DisplayAlert(title, message, accept, cancel);
tcs.SetResult(result);
}
catch (Exception ex) { tcs.SetException(ex); }
});
return tcs.Task.Result;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Sarand.Net.Standard.Mobile.Forms.Utils
{
//=======================================================================
public static class SaxPageUtil
{
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Views
{
//=======================================================================
public class SaxBoxView : BoxView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxBoxView ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,70 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Views
{
//=======================================================================
public class SaxContentView : ContentView
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private bool readOnly = false;
//-------------------------------------------------------------------
// Construction.
public SaxContentView ()
{
}
//-------------------------------------------------------------------
// Properties.
public bool ReadOnly
{
get { return readOnly; }
set { if (readOnly == value) return; readOnly = value; SetControlActivity(); }
}
//-------------------------------------------------------------------
// C o n f i g u r e C o m p o n e n t s
//-------------------------------------------------------------------
protected virtual void ConfigureComponents ()
{
}
//-------------------------------------------------------------------
// C o n t r o l A c t i v i t y
//-------------------------------------------------------------------
protected virtual void SetControlActivity ()
{
SetControlsReadOnly();
}
protected virtual void SetControlsReadOnly ()
{
}
//-------------------------------------------------------------------
// V i e w E v e n t s
//-------------------------------------------------------------------
protected override void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName.EqualsCI(IsEnabledProperty.PropertyName))
{
SetControlActivity();
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Views
{
//=======================================================================
public class SaxFrame : Frame
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxFrame ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Forms.Views
{
//=======================================================================
public class SaxView : View
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SaxView ()
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Tasks
{
//=======================================================================
public static class SaxThreadUtil
{
//-------------------------------------------------------------------
// I n v o k e o n M a i n T h r e a d a n d W a i t
//-------------------------------------------------------------------
// Invoke task on main thread and wait for completion.
public static void BeginInvokeOnMainThreadSync (Action taskFn)
{
var tcs = new TaskCompletionSource<Object>();
Device.BeginInvokeOnMainThread(() =>
{
try
{
taskFn();
tcs.SetResult(null);
}
catch (Exception ex) { tcs.SetException(ex); }
});
}
public static T BeginInvokeOnMainThreadSync<T> (Func<T> taskFn)
{
var tcs = new TaskCompletionSource<T>();
Device.BeginInvokeOnMainThread(() =>
{
try
{
var result = taskFn();
tcs.SetResult(result);
}
catch (Exception ex) { tcs.SetException(ex); }
});
return tcs.Task.Result;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Xamarin.Forms;
namespace Sarand.Net.Standard.Mobile.Utils
{
//=======================================================================
public static class SacsImageUtils
{
//-------------------------------------------------------------------
/// <summary>
/// Method that uses the ImageConverter object in .Net Framework to convert a byte array,
/// presumably containing a JPEG or PNG file image, into an ImageSource.
/// </summary>
public static ImageSource GetImageFromByteArray (byte[] imageAsBytes)
{
return ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+17
View File
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<RootNamespace>Sarand.Net.Standard</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
</ItemGroup>
</Project>