I am using Xamarin Forms to make Cross-platform application and I need to create simple view that user can choose date and time, similar to this:
View that I want to create that i found here: Picker in Xamarin iOS. Solution for Android is ready, but I need to create solution for iOS in the same application
I can not use standard date picker and another standard time picker separately from Xamarin Forms. I need to create custom solution (one view - simple choose both date and time).
I have tried to create view in Xamarin Forms that consist of 2 lists in horizontal orientation (one for date, one for time) but when I select one position, the list is not scrolling to the middle of view and also there is not auto-selecting middle position element when I scroll the list up or down. I want to create something that works like Xamarin-iOS solution: "Date and time picker" but in Xamarin Forms.
I have tried also to create in Xamarin-iOS part of project "date and time picker". I have main.storyboard and view controller but I dont know how to display view from Xamarin-iOS inside Xamarin Forms and pass selected date and time.
Can you help me, please?
If you want to implement date-time picker on Xamarin.Forms in iOS platform.You can use CustomRenderer.
in Forms
create a subclass of Picker
public class MyPicker:Picker
{
public MyPicker()
{
}
}
And add it in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<!-- Place new controls here -->
<local:MyPicker WidthRequest="150" BackgroundColor="AliceBlue"/>
</StackLayout>
in iOS
create the renderer of Picker .And you can set the format of picker as you want.
using System;
using Foundation;
using UIKit;
using ObjCRuntime;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx;
using xxx.iOS;
[assembly:ExportRenderer(typeof(MyPicker),typeof(MyPickerRenderer))]
namespace xxx.iOS
{
public class MyPickerRenderer:PickerRenderer
{
string SelectedValue;
public MyPickerRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
SetTimePicker();
}
}
void SetTimePicker()
{
UIDatePicker picker = new UIDatePicker
{
Mode = UIDatePickerMode.DateAndTime
};
picker.SetDate(NSDate.Now,true);
picker.AddTarget(this,new Selector("DateChange:"),UIControlEvent.ValueChanged);
Control.InputView = picker;
UIToolbar toolbar = (UIToolbar)Control.InputAccessoryView;
UIBarButtonItem done = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done, (object sender, EventArgs click) =>
{
Control.Text = SelectedValue;
toolbar.RemoveFromSuperview();
picker.RemoveFromSuperview();
Control.ResignFirstResponder();
MessagingCenter.Send<Object, string>(this, "pickerSelected", SelectedValue);
});
UIBarButtonItem empty = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace, null);
toolbar.Items = new UIBarButtonItem[] { empty, done };
}
[Export("DateChange:")]
void DateChange(UIDatePicker picker)
{
NSDateFormatter formatter = new NSDateFormatter();
formatter.DateFormat = "MM-dd HH:mm aa"; //you can set the format as you want
Control.Text = formatter.ToString(picker.Date);
SelectedValue= formatter.ToString(picker.Date);
MessagingCenter.Send<Object, string>(this,"pickerSelected",SelectedValue);
}
}
}
And use MessagingCenter to pass the selected date and time.
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<Object, string>(this, "pickerSelected", (sender, arg) => {
Console.WriteLine(arg);
//arg is the selected date and time
});
}
I have uploaded the demo on github .You can download it for test.
The effect
If you want to use native views in Xamarin.Forms it is possible, read it here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/platform/native-views/
Related
I've noticed it's possible to create a mobile app with nested tabs.
Is this possible in Xamarin Forms?
Please see screen shot below:
I can create the bottom tabs on iOS using TabbedPage, but how do I create the nested tabs at the top of the page?
Thank you
The same way you would do on the native app. There are no native nested tabs, so Xamarin can't support it as such thing doesn't exist.
In the native app you have the control at the top (called SegmentedControl on iOS and on Android there is no such control out of the box) where you pick the value and then change the view below manually when it is clicked.
Is this possible in Xamarin Forms?
Yes,of course.You can use CustomRenderer to implement it.Refer to the following code.
in iOS Project . Create a pageRenderer
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using app1;
using app1.iOS;
using UIKit;
using Foundation;
using CoreGraphics;
using ObjCRuntime;
[assembly:ExportRenderer(typeof(MyPage1),typeof(MyPageRenderer))]
namespace app1.iOS
{
public class MyPageRenderer:PageRenderer
{
public MyPageRenderer()
{
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (ViewController != null)
{
NSArray items = NSArray.FromStrings(new string[] { "Courses", "Favourite", "Recent" });
UISegmentedControl segmentedControl = new UISegmentedControl(items)
{
Frame = new CGRect(50, 20, NativeView.Bounds.Width - 100, 35)
};
segmentedControl.SelectedSegment = 0;
segmentedControl.TintColor = UIColor.Red;
segmentedControl.ApportionsSegmentWidthsByContent = true; //Change the width of the segment based on the content of the segment
segmentedControl.AddTarget(this, new Selector("ValueChanged:"), UIControlEvent.ValueChanged);
NativeView.AddSubview(segmentedControl);
}
}
[Export("ValueChanged:")]
void ValueChanged(UISegmentedControl sender)
{
MessagingCenter.Send<Object, int>(this, "ClickSegmentedControl", (int)sender.SelectedSegment);
// switch((int)sender.SelectedSegment){
// case 0:
// break;
// case 1:
// break;
// case 2:
// break;
// default:
// break;
//}
}
}
}
in Forms ,you can subscribe the message .if you want to handle the event in forms when you click the segmented .
public MyPage1()
{
//...
MessagingCenter.Subscribe<Object, int>(this, "ClickSegmentedControl", (sender, arg) =>
{
Console.WriteLine(arg); //arg is num of the segment that you clicked.
});
}
I am trying to make it so users can click a certain substring in a label and it would run a method, for example clicking #hashtag would run OpenHashtag(string hashtagand clicking a #taggedUser would run ViewProfile(taggedUser)
I found this tutorial, except I don't want phone numbers or URLs to be clickable, only hashtags and tagged users.
These are the renders its using
Android
[assembly: ExportRenderer(typeof(BodyLabel), typeof(BodyLabelAndroid))]
namespace SocialNetwork.Droid.Renderers
{
public class BodyLabelAndroid : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
var view = (BodyLabel)Element;
if (view == null) return;
TextView textView = new TextView(Forms.Context);
textView.LayoutParameters = new LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
textView.SetTextColor(view.TextColor.ToAndroid());
// Setting the auto link mask to capture all types of link-able data
textView.AutoLinkMask = MatchOptions.All;
// Make sure to set text after setting the mask
textView.Text = view.Text;
textView.SetTextSize(ComplexUnitType.Dip, (float)view.FontSize);
// overriding Xamarin Forms Label and replace with our native control
SetNativeControl(textView);
}
}
}
IOS
[assembly: ExportRenderer(typeof(BodyLabel), typeof(BodyLabeliOS))]
namespace SocialNetwork.iOS.Renderers
{
public class BodyLabeliOS : ViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
var view = (AwesomeHyperLinkLabel)Element;
if (view == null) return;
UITextView uilabelleftside = new UITextView(new CGRect(0, 0, view.Width, view.Height));
uilabelleftside.Text = view.Text;
uilabelleftside.Font = UIFont.SystemFontOfSize((float)view.FontSize);
uilabelleftside.Editable = false;
uilabelleftside.DataDetectorTypes = UIDataDetectorType.All;
uilabelleftside.BackgroundColor = UIColor.Clear;
SetNativeControl(uilabelleftside);
}
}
}
Android:
Instead of using textView.AutoLinkMask = MatchOptions.All
you can use
Linkify.AddLinks method. Define your regular expression (for example, any word which starts with # or #) and it will work.
But on iOS, it is more complicated I think.
There I see two options:
Use WebView. Parse your string and add "<a href" where needed.
Break your text to pieces and add separate labels for each clickable part. If you want to click only hashtags and tagged users you can add the appropriate labels just below the text. Afterwards you can add tap gesture recognizers to handle the clicks.
In C# windows forms how can I use TextBox.Text property as another property named TextBox.WritePublicText to display text on a multiline textbox? I am editing C# game code that cannot be modified. I am trying to simulate the game code exactly in Visual Studio to edit and then copy directly into the game code. Also I am new to C# so try to dumb it down.
This code displays the text on the windows form textbox named textBox1:
textBox1.Text = "Text to display\r\n"
+ "More Text\r\n"
+ "More Text2\r\n";
This is the code displays the text in game. But I cannot figure out how make it display the text in a windows form textbox.
textBox1.WritePublicText = "Text to display\r\n"
+ "More Text\r\n"
+ "More Text2\r\n";
Other Ideas:
It might be possible to display multiline text another way on windows forms that will allow me to do this.
Create a class and inherit from Windows.Forms.TextBox.
Like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
public class CustomTextBox : TextBox
{
public String WritePublicText
{
get { return Text; }
set { Text = value; }
}
}
}
This tool now is exactly like a normal TextBox, but now it contais a new method called "WritePublicText" that sets and returns a String.
Rebuild your application, then you will see a new tool in your toolBox called CustomTextBox, just drag and drop like any other component.
If you already have to many TextBoxes in you application you could go in your designer file and change the 'TextBox' to 'CustomTextBox' and then rebuild again.
Write a subclass of TextBox which has a public property like so:
public String WritePublicText {
get { return Text; }
set { Text = value; }
}
And use that control instead of TextBox in your UI.
You'll probably have to add a constructor as well to get it to work with the form designer in Visual Studio. Look at the Form1.Designer.cs file in your project (assuming the Form is named Form1; use common sense) to see how the current TextBox is being created; that's the constructor you'll need to duplicate.
As an alternative, if you let use method instead of property (moreover Write... being an verb sounds as a method and doesn't look like a property's name) you can implement extension method:
public static class TextBoxExtensions {
public static void WritePublicText(this TextBox textBox, string value) {
if (null == textBox)
throw new ArgumentNullException("textBox");
textBox.Text = value;
}
}
...
// Extension method instead of property
textBox1.WritePublicText(
"Text to display\r\n"
+ "More Text\r\n"
+ "More Text2\r\n");
Situation :
i am creating a reminder app , i have two pages page1 (for displaying reminders) and page2(for accepting reminder data from user)
my page1.xaml.cs is :
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
IEnumerable<ScheduledNotification> notifications;
private void ResetItemsList()
{
notifications = ScheduledActionService.GetActions<ScheduledNotification>();
NotificationListBox.ItemsSource = notifications;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
//Reset the ReminderListBox items when the page is navigated to.
ResetItemsList();
}
}
}
and this is my logic for creating present in page2.xaml.cs
if ((bool)reminderRadioButton.IsChecked)
{
Reminder reminder = new Reminder(name);
reminder.Title = titleTextBox.Text;
reminder.Content = contentTextBox.Text;
reminder.BeginTime = beginTime;
reminder.ExpirationTime = expirationTime;
reminder.RecurrenceType = recurrence;
// Register the reminder with the system.
ScheduledActionService.Add(reminder);
}
PROBLEM :
In page1.xaml i have binded value of BeginTime property to text property of a textblock . now whenever i run my app i get date as well as time in textblock control , i want only time to be displayed in the textblock what should i do ?
You can format your string using StringFormat. An example would be
<TextBlock Text="{Binding BeginTime, StringFormat='t'}"
The output format would be 2:18 PM. You can modify the StringFormat string to what you like depending on how you want the output to appear. If one of the standard StringFormat specifier from the link above doesn't have the output you need, you can create a custom one.
I am developing a windows phone application. In that I wanted a functionality such that if a text box gets focus date picker should be opened. Similarly another text box will trigger a time picker.
i searched and found that this can be achieved with writing a custom date/time picker. I successfully got the time picker working in this fashion but when I tried to implement the same method for date picker I'm getting the following exception.
"Error HRESULT E_FAIL has been returned from a call to a COM component."
The XAML code for the time and date picker are as follows.
<popUps:CustomTimePicker x:Name="timePicker" Visibility="Collapsed" Value="{Binding SelectedTime, Converter={StaticResource dateTimeConverter}, Mode=TwoWay}" />
<popUps:CustomDatePicker x:Name="datePicker" Visibility="Collapsed" />
The custom date picker class which I wrote for the same is
class CustomDatePicker : DatePicker
{
public void ClickDateTemplateButton()
{
ApplyTemplate();
Button button = (GetTemplateChild("DateTimeButton") as Button);
if (button != null)
{
ButtonAutomationPeer peer = new ButtonAutomationPeer(button);
if (peer != null)
{
IInvokeProvider provider = (peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider);
if (provider != null)
{
provider.Invoke();
}
}
}
}
}
Please help me finding where it went wrong. Thanks.
As a workaround, don't add the customDatePicker in your listBoxItem DataTemplate.
Whenever you want to launch the controls, call the following method. You will need to save the index of your selected listBoxItem in your page's transient State in order to populate the correct Item of your listbox with the selected value, after you return to your page, when the datepicker page closes.
private void LanchDatePicker()
{
datepicker = new CustomDatePicker
{
IsTabStop = false,
MaxHeight = 0,
Value = null
};
datepicker.ValueChanged += DatePicker_OnValueChanged;
LayoutRoot.Children.Add(datepicker);
datepicker.ClickTemplateButton();
}