Sharepoint Webpart Custom toolpart - c#

I added a property to my webpart main.cs
public override ToolPart[] GetToolParts()
{
ToolPart[] toolparts = new ToolPart[4];
WebPartToolPart wptp = new WebPartToolPart();
CustomPropertyToolPart custom = new CustomPropertyToolPart();
CalendarToolPart datumswahl = new CalendarToolPart("Coutdown Datum Wahl");
toolparts[0] = datumswahl;
toolparts[1] = custom;
toolparts[2] = wptp;
return toolparts;
}
I then built this class toolpartClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
namespace Custom_Toolpart.toolparttest
{
class CalendarToolPart : ToolPart
{
public Calendar datumWahl = null;
private void CalendarToolPart_Init(object sender, EventArgs e)
{
datumWahl = new Calendar();
datumWahl.ID = "datumWahl";
SyncChanges();
}
public CalendarToolPart(string strTitle)
{
this.Title = strTitle;
this.Init += new EventHandler(CalendarToolPart_Init);
}
public override void ApplyChanges()
{
//base.ApplyChanges();
EnsureChildControls();
}
public override void SyncChanges()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
base.CreateChildControls();
Controls.Add(datumWahl);
this.ChildControlsCreated = true; //?
}
}
My problem is, that I can't use/call the calendar out of the toolpartClass.cs
What I want to do is, that the selected date is given to the "toolpartUserControl.ascx.cs" (the code behind) where I want to use the date and display a result in the toolpart.ascx
It is no problem to use the "normal" added webpart properties in the toolpartUserControl.ascx.cs, like here
namespace Custom_Toolpart.toolparttest
{
public partial class toolparttestUserControl : UserControl
{
public toolparttest WebPart { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
DateTime datumAuswahl1 = DateTime.Parse(Calendar1.SelectedDate.ToString("MM") + "/" + Calendar1.SelectedDate.ToString("dd") + "/" + Calendar1.SelectedDate.ToString("yyyy"));
DateTime datumJetzt = DateTime.Now;
TimeSpan mySpan = new TimeSpan(-24, 0, 0);
datumJetzt = datumJetzt.Add(mySpan);
TimeSpan laufzeit = datumAuswahl1 - datumJetzt;
string ausgabeLaufzeit = string.Format("{0}", laufzeit.Days);
int i = Convert.ToInt32(ausgabeLaufzeit);
if (i >= 2)
{
lbl_6.Text = "Tage";
}
if (i == 1)
{
lbl_6.Text = "Tag";
}
if (i == 0)
{
lbl_6.Text = "Tage";
lbl_hide.Visible = true;
lbl_1.Visible = false;
lbl_2.Visible = false;
lbl_3.Visible = false;
lbl_6.Visible = false;
}
lbl_2.Text = ausgabeLaufzeit;
if (this.WebPart != null && this.WebPart.CountDown_Text != null)
{
lbl_1.Text = this.WebPart.CountDown_Text.ToString();
}
if (this.WebPart != null && this.WebPart.Event_Text != null)
{
lbl_3.Text = this.WebPart.Event_Text.ToString();
}
if (this.WebPart != null && this.WebPart.Header_Text != null)
{
lbl_4.Text = this.WebPart.Header_Text.ToString();
}
if (this.WebPart != null && this.WebPart.Main_Text != null)
{
lbl_5.Text = this.WebPart.Main_Text.ToString();
}
if (this.WebPart != null && this.WebPart.Link_Edit != null)
{
hyplnk_1.NavigateUrl = this.WebPart.Link_Edit.ToString();
}
if (this.WebPart != null && this.WebPart.Ablauf_Text != null)
{
lbl_hide.Text = this.WebPart.Ablauf_Text.ToString();
}
}
}
}
How can I send the selected date to the toolpartUserControl.ascx.cs class?

Related

Custom Picker Xamarin Android

I have a picker.Please,tell me how to change color of title, the color of items and remove these lines
I have my custompicker and I could change colors of buttons CANCEL,OK
I tried to remove lines
https://forums.xamarin.com/discussion/78693/how-can-i-remove-the-picker-borders-in-forms-for-android
but it does not work
How to change color of SELECT A CAR and AUDI I do not know
You could implement it by using Custom Renderer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using App12.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Color = Android.Graphics.Color;
using Orientation = Android.Widget.Orientation;
[assembly: ExportRenderer(typeof(Picker), typeof(MyPickerRenderer))]
namespace App12.Droid
{
public class MyPickerRenderer:PickerRenderer
{
IElementController ElementController => Element;
public MyPickerRenderer(Context context) : base(context)
{
}
private AlertDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
Control.Click += Control_Click;
Control.SetHintTextColor(Android.Graphics.Color.Red);
Control.SetSingleLine(true);
Control.SetTypeface(null, TypefaceStyle.Bold);
Control.Gravity = GravityFlags.Center;
var gd = new GradientDrawable();
gd.SetStroke(0, Android.Graphics.Color.Transparent);
Control.SetBackground(gd);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.Click -= Control_Click;
//var picker = (Picker)Element;
//picker.PropertyChanged -= Control_Click;
}
base.Dispose(disposing);
}
private void Control_Click(object sender, EventArgs e)
{
Picker model = Element;
picker.SelectionDividerHeight = 0;
var picker = new TextColorNumberPicker(Context);
if (model.Items != null && model.Items.Any())
{
// set style here
picker.MaxValue = model.Items.Count - 1;
picker.MinValue = 0;
picker.SetDisplayedValues(model.Items.ToArray());
picker.WrapSelectorWheel = false;
picker.Value = model.SelectedIndex;
}
var layout = new LinearLayout(Context) { Orientation = Orientation.Vertical };
layout.AddView(picker);
var titleView = new TextView(Context);
titleView.Text = "Select a car";
titleView.TextSize = 20;
titleView.SetTextColor(Color.Red);
titleView.SetBackgroundColor(Color.White);
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, true);
var builder = new AlertDialog.Builder(Context);
builder.SetView(layout);
builder.SetTitle(model.Title ?? "");
builder.SetCustomTitle(titleView);
builder.SetNegativeButton("Cancel ", (s, a) =>
{
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
_dialog = null;
});
builder.SetPositiveButton("Ok ", (s, a) =>
{
ElementController.SetValueFromRenderer(Picker.SelectedIndexProperty, picker.Value);
// It is possible for the Content of the Page to be changed on SelectedIndexChanged.
// In this case, the Element & Control will no longer exist.
if (Element != null)
{
if (model.Items.Count > 0 && Element.SelectedIndex >= 0)
Control.Text = model.Items[Element.SelectedIndex];
ElementController.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
// It is also possible for the Content of the Page to be changed when Focus is changed.
// In this case, we'll lose our Control.
Control?.ClearFocus();
}
_dialog = null;
});
_dialog = builder.Create();
_dialog.DismissEvent += (ssender, args) =>
{
ElementController?.SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
};
_dialog.Show();
Android.Widget.Button btnOk = _dialog.GetButton((int)Android.Content.DialogButtonType.Positive);
btnOk.SetTextColor(Android.Graphics.Color.Blue);
Android.Widget.Button btnCancel = _dialog.GetButton((int)Android.Content.DialogButtonType.Positive);
btnCancel.SetTextColor(Android.Graphics.Color.Gray);
}
}
public class TextColorNumberPicker : NumberPicker
{
public TextColorNumberPicker(Context context) : base(context)
{
}
public override void AddView(Android.Views.View child, int index, ViewGroup.LayoutParams #params)
{
base.AddView(child, index, #params);
UpdateView(child);
}
public void UpdateView(Android.Views.View view)
{
if (view is EditText)
{
((EditText)view).SetTextColor(Color.Red); // set item text color
}
}
}
}
Note : Make sure the Target Framework of the project is the latest stable version (Android Q) .
Override Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer instead of Xamarin.Forms.Platform.Android.PickerRenderer
public class CustomPickerRenderer
: Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer
{
...
}
Reference: https://www.damirscorner.com/blog/posts/20201204-CustomPickerRendererOnAndroid.html

Display PDF File in mobile app from an url

I have a sample pdf URL "http://www.africau.edu/images/default/sample.pdf". I want to show this pdf file and display in my mobile app using Xamarin.Forms. I tried using webviews and some custom renderers but did not work.
public class PdfViewRenderer : WebViewRenderer
{
internal class PdfWebChromeClient : WebChromeClient
{
public override bool OnJsAlert(Android.Webkit.WebView view, string url, string message, JsResult result)
{
if (message != "PdfViewer_app_scheme:print")
{
return base.OnJsAlert(view, url, message, result);
}
using (var printManager = Forms.Context.GetSystemService(Android.Content.Context.PrintService) as PrintManager)
{
printManager?.Print(FileName, new FilePrintDocumentAdapter(FileName, Uri), null);
}
return true;
}
public string Uri { private get; set; }
public string FileName { private get; set; }
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
var pdfView = Element as PdfView;
if (pdfView == null)
{
return;
}
if (string.IsNullOrWhiteSpace(pdfView.Uri) == false)
{
Control.SetWebChromeClient(new PdfWebChromeClient
{
Uri = pdfView.Uri,
//FileName = GetFileNameFromUri(pdfView.Uri)
});
}
Control.Settings.AllowFileAccess = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
LoadFile(pdfView.Uri);
}
private static string GetFileNameFromUri(string uri)
{
var lastIndexOf = uri?.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase);
return lastIndexOf > 0 ? uri.Substring(lastIndexOf.Value, uri.Length - lastIndexOf.Value) : string.Empty;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName != PdfView.UriProperty.PropertyName)
{
return;
}
var pdfView = Element as PdfView;
if (pdfView == null)
{
return;
}
if (string.IsNullOrWhiteSpace(pdfView.Uri) == false)
{
Control.SetWebChromeClient(new PdfWebChromeClient
{
Uri = pdfView.Uri,
// FileName = GetFileNameFromUri(pdfView.Uri)
});
}
LoadFile(pdfView.Uri);
}
private void LoadFile(string uri)
{
if (string.IsNullOrWhiteSpace(uri))
{
return;
}
//Control.Resources = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", string.Format("ms-appx-web:///Assets/Content/{0}", WebUtility.UrlEncode(PdfView.Uri))));
Control.LoadUrl($"file:///android_asset/pdfjs/web/viewer.html?file=file://{uri}");
//Control.LoadUrl(uri);
Control.LoadUrl(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", string.Format("ms-appx-web:///Assets/Content/{0}", WebUtility.UrlEncode(uri))));
}
}
Your XAML
<WebView x:Name="Webview"
HeightRequest="1000"
WidthRequest="1000"
VerticalOptions="FillAndExpand"/>
Put your Webview source like this
Webview.Source = "https://docs.google.com/gview?
embedded=true&url="+"http://www.africau.edu/images/default/sample.pdf";
In Android
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DipsDemoXaml.Droid.Renderer
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.BuiltInZoomControls = true;
Control.Settings.DisplayZoomControls = true;
}
this.Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "Uri") return;
var customWebView = Element as CustomWebView;
if (customWebView != null)
{
Control.LoadUrl(string.Format("file:///android_asset/pdfjs/web/viewer.html?file={0}", string.Format("file:///android_asset/Content/{0}", WebUtility.UrlEncode(customWebView.Uri))));
}
}
}
}
for iOS
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DipsDemoXaml.iOS.Renderes
{
public class CustomWebViewRenderer : ViewRenderer<CustomWebView, UIWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView>
e)
{
base.OnElementChanged(e);
if (Control == null)
{
SetNativeControl(new UIWebView());
}
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
var customWebView = Element as CustomWebView;
string fileName = Path.Combine(NSBundle.MainBundle.BundlePath, string.Format("Content/{0}", WebUtility.UrlEncode(customWebView.Uri)));
Control.LoadRequest(new NSUrlRequest(new NSUrl(fileName, false)));
Control.ScalesPageToFit = true;
}
this.Opaque = false;
this.BackgroundColor = Color.Transparent.ToUIColor();
}
}
}
In shared
namespace DipsDemoXaml.Custom.Renderer
{
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri),typeof(string),
typeof(CustomWebView),default(string))
;
public string Uri
{
get => (string) GetValue(UriProperty);
set => SetValue(UriProperty, value);
}
}
}
In XAML You can Call Like this
<renderer:CustomWebView Uri="{Binding SelectedJournal.Uri}" />
I think Problem in your Custom Rendering You can Create a new property like URI in a string and You can Call the URI you need a way to access Android and iOS webview for that you can call android asset pdf viewer for android and for Ios you can pass a new NSUrl to load the pdf inside your app

Custom TimePickerRenderer is not firing the events to update the TimeProperty

I created a custom TimePicker and the renderers to android and iphone, with the objective to allow for that be nullable. As inspiration, was used the https://xamgirl.com/clearable-datepicker-in-xamarin-forms/
But, for some reason, the event is not firing when the time is set, thats happenen only in android, and more specific, back in android 8.1.
On shared project:
public class NullableTimePicker : TimePicker
{
public NullableTimePicker()
{
Time = DateTime.Now.TimeOfDay;
NullableTime = null;
Format = #"HH\:mm";
}
public string _originalFormat = null;
public static readonly BindableProperty PlaceHolderProperty =
BindableProperty.Create(nameof(PlaceHolder), typeof(string), typeof(NullableTimePicker), " : ");
public string PlaceHolder
{
get { return (string)GetValue(PlaceHolderProperty); }
set
{
SetValue(PlaceHolderProperty, value);
}
}
public static readonly BindableProperty NullableTimeProperty =
BindableProperty.Create(nameof(NullableTime), typeof(TimeSpan?), typeof(NullableTimePicker), null, defaultBindingMode: BindingMode.TwoWay);
public TimeSpan? NullableTime
{
get { return (TimeSpan?)GetValue(NullableTimeProperty); }
set { SetValue(NullableTimeProperty, value); UpdateTime(); }
}
private void UpdateTime()
{
if (NullableTime != null)
{
if (_originalFormat != null)
{
Format = _originalFormat;
}
}
else
{
Format = PlaceHolder;
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext != null)
{
_originalFormat = Format;
UpdateTime();
}
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == TimeProperty.PropertyName ||
(
propertyName == IsFocusedProperty.PropertyName &&
!IsFocused &&
(Time == DateTime.Now.TimeOfDay)))
{
AssignValue();
}
if (propertyName == NullableTimeProperty.PropertyName && NullableTime.HasValue)
{
Time = NullableTime.Value;
if (Time == DateTime.Now.TimeOfDay)
{
//this code was done because when date selected is the actual date the"DateProperty" does not raise
UpdateTime();
}
}
}
public void CleanTime()
{
NullableTime = null;
UpdateTime();
}
public void AssignValue()
{
NullableTime = Time;
UpdateTime();
}
}
On Android project:
public class NullableTimePickerRenderer : ViewRenderer<NullableTimePicker, EditText>
{
public NullableTimePickerRenderer(Context context) : base(context)
{
}
TimePickerDialog _dialog;
protected override void OnElementChanged(ElementChangedEventArgs<NullableTimePicker> e)
{
base.OnElementChanged(e);
this.SetNativeControl(new Android.Widget.EditText(Context));
if (Control == null || e.NewElement == null)
return;
this.Control.Click += OnPickerClick;
if (Element.NullableTime.HasValue)
Control.Text = DateTime.Today.Add(Element.Time).ToString(Element.Format);
else
this.Control.Text = Element.PlaceHolder;
this.Control.KeyListener = null;
this.Control.FocusChange += OnPickerFocusChange;
this.Control.Enabled = Element.IsEnabled;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Xamarin.Forms.TimePicker.TimeProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.TimePicker.FormatProperty.PropertyName)
SetTime(Element.Time);
}
void OnPickerFocusChange(object sender, Android.Views.View.FocusChangeEventArgs e)
{
if (e.HasFocus)
{
ShowTimePicker();
}
}
protected override void Dispose(bool disposing)
{
if (Control != null)
{
this.Control.Click -= OnPickerClick;
this.Control.FocusChange -= OnPickerFocusChange;
if (_dialog != null)
{
_dialog.Hide();
_dialog.Dispose();
_dialog = null;
}
}
base.Dispose(disposing);
}
void OnPickerClick(object sender, EventArgs e)
{
ShowTimePicker();
}
void SetTime(TimeSpan time)
{
Control.Text = DateTime.Today.Add(time).ToString(Element.Format);
Element.Time = time;
}
private void ShowTimePicker()
{
CreateTimePickerDialog(this.Element.Time.Hours, this.Element.Time.Minutes);
_dialog.Show();
}
void CreateTimePickerDialog(int hours, int minutes)
{
NullableTimePicker view = Element;
_dialog = new TimePickerDialog(Context, (o, e) =>
{
view.Time = new TimeSpan(hours: e.HourOfDay, minutes: e.Minute, seconds: 0);
view.AssignValue();
((IElementController)view).SetValueFromRenderer(VisualElement.IsFocusedProperty, false);
Control.ClearFocus();
_dialog = null;
}, hours, minutes, true);
_dialog.SetButton("ok", (sender, e) =>
{
SetTime(Element.Time);
this.Element.Format = this.Element._originalFormat;
this.Element.AssignValue();
});
_dialog.SetButton2("clear", (sender, e) =>
{
this.Element.CleanTime();
Control.Text = this.Element.Format;
});
}
}
On iOS project:
public class NullableTimePickerRenderer : TimePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
base.OnElementChanged(e);
var timePicker = (UIDatePicker)Control.InputView;
timePicker.Locale = new NSLocale("no_nb");
if (e.NewElement != null && this.Control != null)
{
this.UpdateDoneButton();
this.AddClearButton();
this.Control.BorderStyle = UITextBorderStyle.Line;
Control.Layer.BorderColor = UIColor.LightGray.CGColor;
Control.Layer.BorderWidth = 1;
if (Device.Idiom == TargetIdiom.Tablet)
{
this.Control.Font = UIFont.SystemFontOfSize(25);
}
}
}
private void UpdateDoneButton()
{
var toolbar = (UIToolbar)Control.InputAccessoryView;
var doneBtn = toolbar.Items[1];
doneBtn.Clicked += (sender, args) =>
{
NullableTimePicker baseTimePicker = this.Element as NullableTimePicker;
if (!baseTimePicker.NullableTime.HasValue)
{
baseTimePicker.AssignValue();
}
};
}
private void AddClearButton()
{
var originalToolbar = this.Control.InputAccessoryView as UIToolbar;
if (originalToolbar != null && originalToolbar.Items.Length <= 2)
{
var clearButton = new UIBarButtonItem("clear", UIBarButtonItemStyle.Plain, ((sender, ev) =>
{
NullableTimePicker baseTimePicker = this.Element as NullableTimePicker;
this.Element.Unfocus();
this.Element.Time = DateTime.Now.TimeOfDay;
baseTimePicker.CleanTime();
}));
var newItems = new List<UIBarButtonItem>();
foreach (var item in originalToolbar.Items)
{
newItems.Add(item);
}
newItems.Insert(0, clearButton);
originalToolbar.Items = newItems.ToArray();
originalToolbar.SetNeedsDisplay();
}
}
}
This code works fine on iOS and Android version 8.1 or higher, but in lower version, this just not fire the event to set time, setting always the default time.
I'm also provided a git repo with the code, maybe, make easily understand my problem.
https://github.com/aismaniotto/Nullable24hTimePicker
Thanks for your help. After more digging on code and debugging, I realize the problem was on OkButton implementation. On Android 8, apparently, the callback from the TimePickerDialog was called before the OkButton implementation e what was there, is ignored. On the older version, the OKButton implementation was called before and, for some reason, cancel the invocation of the callback.
That way, removing the OkButton implementation, the problem was solved... remembering that on the working version, was ignored anyway. Eventually, I will commit to the repository, to be registered.
Thanks a lot.

Xamarin Forms Maps Custom Android Renderer GetMapAsync Not Calling OnMapReady

UPDATE
I am running into an issue with GetMapAsync Not calling OnMapReady I am able to suppress the error by checking if the map is null the map will then load with non custom markers. If I then move the map slightly OnMapReady will load and the custom markers will then be displayed. Below is my custom renderer class, if anyone else has ran into this issue I would be very grateful to hear your resolution.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Android.Content;
using Android.Gms.Maps;
using Android.Gms.Maps.Model;
using Android.Views;
using Android.Widget;
using BSi.Mobile.Events.Controls;
using BSi.Mobile.Events.Droid.Renderers;
using BSi.Mobile.Events.Events;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.Android;
using View = Xamarin.Forms.View;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace BSi.Mobile.Events.Droid.Renderers
{
public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
{
GoogleMap map;
IList<CustomPin> customPins;
private CustomPin selectedPin;
bool isDrawn;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
map.InfoWindowClick -= OnInfoWindowClick;
map.MarkerClick -= OnMarkerClick;
map.MapClick -= OnMapClick;
}
if (e.NewElement != null)
{
var formsMap = (CustomMap)e.NewElement;
customPins = formsMap.CustomPins;
selectedPin = formsMap.SelectedPin;
((MapView)Control).GetMapAsync(this);
}
}
public void OnMapReady(GoogleMap googleMap)
{
map = googleMap;
map.InfoWindowClick += OnInfoWindowClick;
map.MarkerClick += OnMarkerClick;
map.MapClick += OnMapClick;
map.SetInfoWindowAdapter(this);
SetMapMarkers();
}
private void SetMapMarkers()
{
map.Clear();
foreach (var pin in customPins)
{
addMarker(pin, false);
}
isDrawn = true;
if (selectedPin != null)
{
addMarker(selectedPin, true);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName.Equals("VisibleRegion") && !isDrawn && map != null)
{
SetMapMarkers();
}
else if (e.PropertyName.EndsWith("SelectedPin") && map != null)
{
var customMap = sender as CustomMap;
selectedPin = customMap?.SelectedPin;
if (selectedPin != null)
{
addMarker(selectedPin, true);
}
}
}
private void addMarker(CustomPin pin, bool isSelected)
{
var marker = new MarkerOptions();
marker.SetPosition(new LatLng(pin.Pin.Position.Latitude, pin.Pin.Position.Longitude));
marker.SetTitle(pin.Pin.Label);
marker.SetSnippet(pin.Pin.Address);
switch (pin.Id)
{
case "Convention":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.star));
break;
case "cafe":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.cafe));
break;
case "bar":
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.bar));
break;
default:
marker.SetIcon(BitmapDescriptorFactory.FromResource(Resource.Drawable.restaurant));
break;
}
var selectedMarker = map.AddMarker(marker);
if (isSelected)
selectedMarker.ShowInfoWindow();
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
//Catches Exception incase user needs to update google play services
try
{
base.OnLayout(changed, l, t, r, b);
if (changed)
{
isDrawn = false;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPin(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPin(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
switch (customPin.Id)
{
case "Conference":
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
break;
default:
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
break;
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
var infoPhone = view.FindViewById<TextView>(Resource.Id.InfoWindowPhone);
var infoWebsite = view.FindViewById<TextView>(Resource.Id.InfoWindowWebsite);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
else
{
infoTitle.Visibility = ViewStates.Gone;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
else
{
infoSubtitle.Visibility = ViewStates.Gone;
}
if (infoPhone != null && customPin.Phone != null)
{
infoPhone.Text = customPin.Phone;
}
else
{
infoPhone.Visibility = ViewStates.Gone;
}
if (infoWebsite != null && customPin.Url != null)
{
infoWebsite.Text = customPin.Url;
}
else
{
infoWebsite.Visibility = ViewStates.Gone;
}
return view;
}
return null;
}
public Android.Views.View GetInfoWindow(Marker marker)
{
return null;
}
CustomPin GetCustomPin(Marker annotation)
{
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Pin.Position == position)
{
return pin;
}
}
return null;
}
private void OnMarkerClick(object sender, GoogleMap.MarkerClickEventArgs e)
{
e.Handled = false;
App.EventAggregator?.GetEvent<MapClickedEvent>().Publish(new Pin { Position = new Position(e.Marker.Position.Latitude, e.Marker.Position.Longitude), Label = e.Marker.Title});
}
private void OnMapClick(object sender, GoogleMap.MapClickEventArgs e)
{
App.EventAggregator?.GetEvent<MapClickedEvent>().Publish(null);
}
}
}
I found a work around to fix this issue I moved the code where I setup the map markers inside its own function, from there I call that function inside OnElementPropertyChanged as with the normal execution. This sets up the markers when the map moves. To load the custom markers when the map loads I also called setup markers inside onMapReady. My Code Above now reflects a working solution, I hope I have helped anyone else out who may run into this issue Cheers!

Text-property of my ASP.NET Composite-control doesn't set text-changes

I have build a composite control which renders a TextControl or a RADEditor control, dependable of a property a set. Both rendered controls have a Text-property. The problem is that when I change the Textvalue on my webpage (when it is running) it won't set the new Text-value but the old Textvalue instead.
Does anyboy know what I'm doing wrong?
Below the code of my composite-control.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;
using System.Web.UI.HtmlControls;
using Framework.WebControls;
namespace Components.Broadcasting.Controls
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:TextControl runat=server></{0}:TextControl>")]
public class TextControl : CompositeControl, INamingContainer, IDisposable
{
//private Control _myControl;
private Label _myLabel;
private HtmlGenericControl _contentContainer;
private HtmlGenericControl _labelBlock;
private HtmlGenericControl _inputBlock;
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return base.Controls;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
[Bindable(true)]
[Category("Campagne Broadcasting")]
[DefaultValue("Naam label")]
[Description("Label horende bij het contenttype")]
public string Label
{
get
{
String s = (String)ViewState["label"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["label"] = value;
}
}
[Bindable(true)]
[Category("Campagne Broadcasting")]
[DefaultValue(XMLElementType.Heading)]
[Description("Nog in te vullen")]
public XMLElementType XMLElementType
{
get
{
if (ViewState["textContentType"] == null) return XMLElementType.Heading;
return (XMLElementType)ViewState["textContentType"];
}
set
{
ViewState["textContentType"] = value;
}
}
[Bindable(true)]
[Category("Campagne Broadcasting")]
[DefaultValue("0")]
[Description("Layoutposition of the contentitem")]
public int ContentPosition
{
get
{
if (ViewState["contentPosition"] == null) return 0;
return (int)ViewState["contentPosition"];
}
set
{
ViewState["textContentType"] = value;
}
}
[Bindable(true)]
[Category("Campagne Broadcasting")]
[DefaultValue("0")]
[Description("Layoutposition of the contentitem")]
public XmlOutputGroup XMLOutputGroup
{
get
{
if (ViewState["xmlOutputGroup"] == null) return 0;
return (XmlOutputGroup)ViewState["xmlOutputGroup"];
}
set
{
ViewState["xmlOutputGroup"] = value;
}
}
protected override void RecreateChildControls()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
Controls.Clear();
string containerClass = "contentContainer";
string labelBlock = "labelBlock";
string inputBlock = "inputBlock";
_myLabel = new Label();
_myLabel.Text = Label;
_contentContainer = new HtmlGenericControl("div");
_contentContainer.Attributes["class"] = containerClass;
_labelBlock = new HtmlGenericControl("div");
_labelBlock.Attributes["class"] = labelBlock;
_inputBlock = new HtmlGenericControl("div");
_inputBlock.Attributes["class"] = inputBlock;
_contentContainer = new HtmlGenericControl("div");
_contentContainer.Attributes["class"] = containerClass;
_labelBlock.Controls.Add(_myLabel);
if (XMLElementType == XMLElementType.Heading)
{
TextBox _myControl = new TextBox();
_myControl.Text = this.Text;
_inputBlock.Controls.Add(_myControl);
}
else if (XMLElementType == XMLElementType.Content)
{
RadEditor _myControl = new RadEditor();
_myControl.Content = this.Text;
_inputBlock.Controls.Add(_myControl);
}
else if (XMLElementType == XMLElementType.SlideTypeName)
{
TextBox _myControl = new TextBox();
_myControl.Text = this.Text;
_inputBlock.Controls.Add(_myControl);
}
else if (XMLElementType == XMLElementType.Image)
{
ImageUploader _myControl = new ImageUploader();
_inputBlock.Controls.Add(_myControl);
}
_contentContainer.Controls.Add(_labelBlock);
_contentContainer.Controls.Add(_inputBlock);
this.Controls.Add(_contentContainer);
}
protected override void RenderContents(HtmlTextWriter output)
{
_contentContainer.RenderControl(output);
}
}
}
Thanks in advance
Kind regards, Patrick
You are exposing properties such as Label, Text, but only using them in CreateChildControls - which is too early in the page lifecycle. The easiest way to deal with this is to delegate the property to a child control, as in the example below for the Label property. You could handle the Text property similarly.
Alternatively, you can set the properties on your child controls in your RenderContents override, but this adds some complexity.
public string Label
{
get
{
EnsureChildControls();
return _myLabel.Text;
}
set
{
EnsureChildControls();
_myLabel.Text = value;
}
}

Categories