Clear Datepicker's value after clicking the submit button in xamarin form - xamarin.forms

My problem is, the data which is date entered by user is doesn't after submit button. So I have fields in my registration page and A button to save in my database.
This is what I've tried.
//My Datepicker Design
`
<local:BirthdayDatePickerControl
TextColor="Black"
x:Name="entryField_DateOfBirth"
/>
`
The purpose that I create a custom control in my datepicker is to put an placeholder iny my datepicker field.
//my Birthdaypickercontrol.cs
`
public class BirthdayDatePickerControl : DatePicker
{
public event EventHandler ClearRequested;
// for my placeholder "birthdate"
public static readonly BindableProperty EnterTextProperty = BindableProperty.Create(propertyName: "Placeholder", returnType: typeof(string), declaringType: typeof(BirthdayDatePickerControl), defaultValue: default(string));
public string Placeholder { get; set; }
//function to clear data of my datepicker input
public void clear()
{
if (ClearRequested != null)
{
ClearRequested(this, EventArgs.Empty);
}
}
}
`
In my project.android, I create a birthday renderer.cs
//so this is my code
`
[assembly: ExportRenderer(typeof(BirthdayDatePickerControl), typeof(BirthdayDatePickerRenderer))]
public class BirthdayDatePickerRenderer : DatePickerRenderer
{
public BirthdayDatePickerRenderer(Context context) : base(context)
{
}
EditText editText;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
//code for placeholder
if (Control != null)
{
Control.Text = "Birth Date";
}
//end here
//code start here for clearing the data in datepicker input field
editText = Control as EditText;
if (e.NewElement != null)
{
BirthdayDatePickerControl bdaydatePickerControl = e.NewElement as BirthdayDatePickerControl;
bdaydatePickerControl.ClearRequested += DatePickerControl_ClearRequested;
}
//end here
}
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
editText.Text = string.Empty;
}
}
`
The codes I pasted will anyway, but..
Assuming in the onload of my registration page, The UI will be like this( pic for reference and ctto to google). After user choose birthdate, example 12/1/22 and hit submit button(all data save in to database). The problem is the placeholder "birthdate" remove/disappear Like this, then if I click the datepicker input field to check the date, the date is still pointing in 12/1/22. What I expected is after performing the ClearData(), the date should be reset in today's date.
//this is my ClearData() function
`
public void ClearData()
{
entryField_DateOfBirth.clear();// this is what I tried and got an bad ouput
}
`

You said:
What I expected is after performing the ClearData(), the date should be reset in today's date.
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
editText.Text = string.Empty;
}
Change to this:
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
BirthdayDatePickerControl birthdayDate = sender as BirthdayDatePickerControl;
birthdayDate.Date = DateTime.Now;
editText.Text = "Birth Date";
}

Related

Get the value of custom Datepicker and save it to firebase database

My problem is I want to insert datepicker's value to firebase but Idk how to do it.
I already made an custom date picker but the use of it is to make an placeholder "birth date"
This is my xaml;
<frame //some property here>
<stacklayout //some property here>
<frame //some property here>
<image //some property here/>
<grid>
<local:BirthdayDatePickerControl x:Name="entryField_DateOfBirth" >
</local:BirthdayDatePickerControl >
</grid>
</frame>
</stacklayout>
</frame>
This is my code(Myproj):
Datepickerctrl.cs
public class DatePickerCtrl:DatePicker
{
public static readonly BindableProperty EnterTextProperty = BindableProperty.Create(propertyName: "Placeholder", returnType: typeof(string), declaringType: typeof(DatePickerCtrl), defaultValue: default(string));
public string Placeholder { get; set; }
}
this file or code also is save to (Myproj)
BirthdayDatePickerControl.cs:
public class BirthdayDatePickerControl : DatePicker
{
public static readonly BindableProperty EnterTextProperty = BindableProperty.Create(propertyName: "Placeholder", returnType: typeof(string), declaringType: typeof(BirthdayDatePickerControl), defaultValue: default(string));
public string Placeholder { get; set; }
}
This is my code(Myproj.android):
[assembly: ExportRenderer(typeof(BirthdayDatePickerControl), typeof(BirthdayDatePickerRenderer))] // this line is outside of my namespace in BirthdayDatePickerRenderer.cs
BirthdayDatePickerRenderer.cs
public class BirthdayDatePickerRenderer : DatePickerRenderer
{
public BirthdayDatePickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.Text = "Birth Date";
}
}
}
My expected output is still I can place an placeholder to my datepicker UI, and also get that data from datepicker and same it to firebase.
I tried some trial and error
This is what I've done
async public void signButton_Clicked(System.Object sender, System.EventArgs e)
{
/*
some code here like assigning firstname or lastname and etc.
*/
string dateOfBirth = entryField_DateOfBirth.ToString();
CUSTOMER customer = new CUSTOMER();
customer.CusBirthOfDate = dateOfBirth;
var Savedata = await customerRepo.Save(customer);
}
I think you have done most of the work. Just make a small change to the Button Clicked handler:
async public void signButton_Clicked(System.Object sender, System.EventArgs e)
{
...
var date = entryField_DateOfBirth.Date.ToString().Split(" ")[0]; //get the date
...
}
If you want to set the default placeholder of Datepicker to "Birth Date", you should still use a custom render, otherwise xamarin forms Datepicker cannot recognize this kind of string. For more info, you could refer to Xamarin.Forms DatePicker.
Hope it works for you.

Updating content between tabs binded by Preference

I am using a tabbed app and I have a button on one tab, when the user clicks then it increments a Preference and I want to update its value on another tab that is Binded to a label. I tried to experiment with MVVM but I couldnt figure it out.
Page 1 view:
public partial class Page1View: ContentPage
{
public Page1View()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0)+1);
}
}
Page 2 Viewmodule:
public class Page2ViewModule : INotifyPropertyChanged
{
public int Total
{
get => Preferences.Get(nameof(Total), 0);
set
{
if (Preferences.Get(nameof(Total),0) == value)
return;
Preferences.Set(nameof(Total), value);
OnPropertyChanged(nameof(Total));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here's what I done with MessagingCenter. On the button click event I sent a message like this:
private void Button_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0)+1);
MessagingCenter.Send<Page>(this, "test");
}
In the Page2 view module I added a constructor that subscribes to message:
public Page2ViewModule()
{
MessagingCenter.Subscribe<Page>(this, "test", (p) =>
{
Total = Preferences.Get(nameof(Total), 0);
});
}
And that still doesn't work. But I'm not sure would this be the best way to do it? Or is there a more efficient way?
For Jason's question: Page2 already been created and the Subscribe method execute before you call Send, I test at my side, Page2 is been created and the Subscribe method execute after you call Send, so I think it works fine using MessagingCenter to notify each page when the Preference has been updated.
Tab one Page.
private void btn1_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0) + 1);
label1.Text = Preferences.Get("Total", 0).ToString();
MessagingCenter.Send<Page>(this, "test");
}
Tab two page.
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding Total}" />
</StackLayout>
</ContentPage.Content>
public partial class Tab2 : ContentPage
{
public Tab2()
{
InitializeComponent();
this.BindingContext = new Page2ViewModule();
}
}
public class Page2ViewModule : ViewModelBase
{
private int _Total;
public int Total
{
get { return _Total; }
set
{
_Total = value;
RaisePropertyChanged("Total");
}
}
public Page2ViewModule()
{
MessagingCenter.Subscribe<Page>(this, "test", (p) =>
{
Total = Preferences.Get("Total", 0);
});
}
}

Getting selected value from Picker in Xamarin

I am getting data from a web service and I am loading it in Picker. Now I want to call a new web service to get some data related to selected item. But I am not getting that selected item.
I am using below class model to get data from web service and loading it in Picker.
public class ModelGetEmployeeList
{
public string ServiceStatus { get; set; }
public List<EmployeeList> EmpList { get; set; }
}
public class EmployeeList
{
public string uid { get; set; }
public string fname { get; set; }
public string lname { get; set; }
}
This is how I loaded data in Picker:
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync ();
var Items = JsonConvert.DeserializeObject <ModelGetEmployeeList> (content);
foreach(EmployeeList emp in Items.EmpList)
{
pickerEmployee.Items.Add(emp.uid.ToString()+"-"+emp.fname.ToString()+" "+emp.lname.ToString());
}
}
Now I am implementing SelectedIndexChanged event like this:
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as EmployeeList;
var selectedItem = item.uid;
DisplayAlert (selectedItem.ToString (), "OK", "OK");
}
}
But its giving me an error that above method has wrong signature.
You can take sellected value with this:
string selectedEmployee = string.Empty;
selectedEmployee = pickerEmployee.Items[pickerEmployee.SelectedIndex];
According to the Xamarin.Forms Picker documentation SelectedIndexChanged event is expecting delegate which matches EventHandler delegate (EventHandler documentation)
So, you have to change signature of your method :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
...
}
Your signature is wrong.
Also the following code is wrong:
var item = sender as EmployeeList;
var selectedItem = item.uid;
Please find the corrected version below :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = PickerEmployee[SelectedIndex];
DisplayAlert (selectedItem, "OK", "OK");
}
}
The Xamarin Forms picker will get you only the string which was added to the list and not the object.
If you need the object either you can use the selectedIdex on your orginal lsit to get the object as :
var selectedEmp = Items.EmpList[SelectedIndex];
Or you can use a Bindable Picker.
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = (EmployeeList)PickerEmployee.SelectedItem;
DisplayAlert (selectedItem.fname, "OK", "OK");
}
}
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as Picker;
var selectedItem = item.SelectedItem as EmployeeList;
var uid =selectedItem.uid;
DisplayAlert (uid .ToString (), "OK", "OK");
}
}
The Items collection is a list of strings so you can get the currently selected value using SelectedIndex
var selectedValue = picker.Items [picker.SelectedIndex];
If you are using binding then yes, the exposed property is the SelectedIndex.
For more info click here
//How to get value of picker in Xamarin forms
//We are getting Text and Value from API
//xaml page
<controls:BorderlessPicker
x:Name="Pickdoctype"
ItemDisplayBinding="{Binding text}"
SelectedIndexChanged="Pickdoctype_SelectedIndexChanged"
HorizontalOptions="FillAndExpand"
Title="Enter Document Type"
FontSize="20"
TextColor="Gray">
</controls:BorderlessPicker>
// xaml.cs page
private void Pickdoctype_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
DocumentTypeModel selectedItem = (DocumentTypeModel)Pickdoctype.SelectedItem;
updatePickerValue = selectedItem.value;
}
catch (Exception ex)
{
}
}
// class
public class DocumentTypeModel
{
public string text { get; set; }
public string value { get; set; }
}

Getting data back from composite control added to placeholder on postback

I'm trying to create a factory pattern based on the CompositeControl class.
Everything is working fine. Except as I understand it I have to add the control back onto the placeholder control on my actual page. I've searched around for examples and got one to almost work expect it only worked on the first postback.
I've created a sample here and I'll post all the code here.
Code on my webpage, the most important here is I guess on OnInit where I'm trying to add the control back onto the placeholder, I guess this is what I might be doing wrong.
using SampleControls;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Setup First Control
Session.Clear();
BaseCompositeControl ltb = new LabelTextBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Check if the post back and recreate the control
if (IsPostBack)
{
int c = this.Form.Controls.Count;
for (int i = 0; i < Session.Count; i++)
{
if (Session[i].ToString().Contains("Control"))
{
this.PlaceHolder1.Controls.Add((BaseCompositeControl)(Session[i]));
}
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//Get Postback Date
BaseCompositeControl oltb = (BaseCompositeControl)this.PlaceHolder1.Controls[0];
lblPstBck.Text = oltb.Text;
this.PlaceHolder1.Controls.Clear();
Session.Clear();
//Load next Control
BaseCompositeControl ltb = new LabelCheckBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
This is composite control classes, I don't know if I have to do something here to handle the viewstate or how?
public abstract class BaseCompositeControl : CompositeControl
{
protected string _Title;
public abstract string Text
{
get;
set;
}
public string Title
{
get { EnsureChildControls();
return _Title; }
set { EnsureChildControls();
_Title = value; }
}
protected override void CreateChildControls()
{
// Clears child controls
Controls.Clear();
// Build the control tree
CreateControlHierarchy();
ClearChildViewState();
}
protected abstract void CreateControlHierarchy();
}
TextBox control
public class LabelCheckBox : BaseCompositeControl
{
protected CheckBox _CheckBox;
public override string Text
{
get
{
EnsureChildControls();
return _CheckBox.Checked.ToString(); ;
}
set
{
EnsureChildControls();
_CheckBox.Checked = Convert.ToBoolean(value);
}
}
protected override void CreateControlHierarchy()
{
_CheckBox = new CheckBox();
Label l = new Label();
// Configure controls
l.Text = "Second Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_CheckBox);
}
}
Checkbox control
public class LabelTextBox : BaseCompositeControl
{
protected TextBox _Text;
public override string Text
{
get
{
EnsureChildControls();
return _Text.Text;
}
set
{
EnsureChildControls();
_Text.Text = value;
}
}
protected override void CreateControlHierarchy()
{
Label l = new Label();
_Text = new TextBox();
// Configure controls
l.Text = "First Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_Text);
}
}
I asked this a long time ago,
But I think this is how you should do it. Using a factory pattern for user controls.
http://weblogs.asp.net/sfeldman/archive/2007/12/17/factory-pattern-for-user-controls.aspx

Custom Control Properties not initializing properly

The First - LblTextBox:
A label and textbox that have a LabelText field that can be set to change the label text
The Second - LoginCtl:
A login control that has two instances of LblTextBox for user name, password and a submit button
I want to control the tag rendering of these controls for formatting so I am not overriding CreateChildControls() to get the job done.
My issue is that the controls are rendered but none of the OnInit() code in either controls takes hold (blank labels, css styles not applied, etc..).
Any direction would be great!
public class LblTextBox : CompositeControl
{
public string LabelText { get; set; }
public string Text { get; set; }
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
public LblTextBox()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
}
protected override void OnInit(EventArgs e)
{
label.ID = "lblTextBox";
label.Text = string.Format("{0}:", LabelText);
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Div);
label.RenderControl(writer);
input.RenderControl(writer);
evalReqField.RenderControl(writer);
writer.RenderEndTag();
}
}
public class LoginCtl : CompositeControl
{
public string UserName
{
get
{
return (ltbUser != null) ? ltbUser.Text : string.Empty;
}
set
{
if (ltbUser != null)
ltbUser.Text = value;
}
}
public string Password
{
get
{
return (ltbPass != null) ? ltbPass.Text : string.Empty;
}
set
{
if (ltbPass != null)
ltbPass.Text = value;
}
}
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
public LoginCtl()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
}
protected override void OnInit(EventArgs e)
{
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "LoginCtlDiv");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
ltbUser.RenderControl(writer);
ltbPass.RenderControl(writer);
btnSubmit.RenderControl(writer);
writer.RenderEndTag();
}
}
The goal was to be able to set properties in the aspx Markup using the control. However, the properties were never initialized.
My error was in the understanding of using CreateChildControls() and RenderChildren(..)
I thought that it was to use one or the other. Instead, I instantiate all the child controls and add them in CreateChildControls().
In order to load the properties, I wait till the OnPreRender() event. The controls will all be loaded and so will the data. Then I make the final changes before the control is rendered to the page.
Another little note, I really wanted to change the default tag that is wrapped around my controls for display purposes (ASP will wrap it with a span by default). So if you want a block level elem this will cause a problem. If you override the TagKey property and set it to an enum elem it will use that instead of the default span tag.
I restructured it as the following:
public class LblTextBox : CompositeControl
{
protected override void OnPreRender(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
base.OnPreRender(e);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void CreateChildControls()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
label.ID = "lblTextBox";
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
Controls.Add(label);
Controls.Add(input);
Controls.Add(evalReqField);
base.CreateChildControls();
}
public string LabelText { get; set; } //label text
public string Text { get; set; } //text in textbox
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
}
public class LoginCtl : CompositeControl
{
protected override void CreateChildControls()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
ltbPass.MargBetween = "10px";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
Controls.Add(ltbUser);
Controls.Add(ltbPass);
Controls.Add(btnSubmit);
}
//..
//..
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
I don't remember why (I'll try to recall), but I had very similar problem few months ago, and my solution was to initialize all of properties except of "ID" in OnLoad event handler:
protected override void OnLoad(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
Hope this helps

Resources