I want a frame with a dashed border (as shown in the image). I am looking for UWP Renderer if anyone has any suggestions on that please share them with me. I am stuck with this.
Custom Renderer for Dashed Border of frame in UWP Xamarin
Current there is not such Dashed Border of frame in UWP Xamarin, but you can make it with Rectangle and set available StrokeDashArray to implement it and then use ViewRenderer to render it within Xamarin. We will share DashedBorderRenderer below, for the complete control please refer code sample here.
public class DashedBorderRenderer : ViewRenderer<DashedBorder, DottedBorder>
{
DottedBorder _dottedBorder;
FrameworkElement _navtiveContent;
double defaultPadding = 2;
bool isOpened;
public DashedBorderRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<DashedBorder> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
_navtiveContent.Loaded -= Native_Loaded;
_navtiveContent.SizeChanged -= Native_SizeChanged;
}
if (e.NewElement != null)
{
if (Control != null)
{
var stroke = Element.DashedStroke == 0 ? Element.DashedStroke : 2.0;
var borderColor = Element.BorderColor.ToWindowsColor() == null ? Element.BorderColor.ToWindowsColor() : Colors.Red;
Control.DashedStroke = new Windows.UI.Xaml.Media.DoubleCollection() { stroke };
Control.StrokeBrush = new Windows.UI.Xaml.Media.SolidColorBrush(borderColor);
}
else
{
_dottedBorder = new DottedBorder();
_navtiveContent = Element.Content.GetOrCreateRenderer().GetNativeElement() as FrameworkElement;
_navtiveContent.Loaded += Native_Loaded;
_navtiveContent.SizeChanged += Native_SizeChanged;
var stroke = Element.DashedStroke == 0 ? 2.0 : Element.DashedStroke;
var borderColor = Element.BorderColor.ToWindowsColor() == null ? Element.BorderColor.ToWindowsColor() : Colors.Red;
_dottedBorder.DashedStroke = new Windows.UI.Xaml.Media.DoubleCollection() { stroke };
_dottedBorder.StrokeBrush = new Windows.UI.Xaml.Media.SolidColorBrush(borderColor);
SetNativeControl(_dottedBorder);
}
}
}
private void Native_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateSize(sender);
}
private void Native_Loaded(object sender, RoutedEventArgs e)
{
UpdateSize(sender);
}
private void UpdateSize(object sender)
{
var content = sender as FrameworkElement;
if (content is Windows.UI.Xaml.Controls.Image)
{
if (!isOpened)
{
(content as Windows.UI.Xaml.Controls.Image).ImageOpened += (s, e) =>
{
isOpened = true;
var image = sender as Windows.UI.Xaml.Controls.Image;
_dottedBorder.Height = image.ActualHeight + defaultPadding;
_dottedBorder.Width = image.ActualWidth + defaultPadding;
};
}
else
{
_dottedBorder.Height = content.ActualHeight + defaultPadding;
_dottedBorder.Width = content.ActualWidth + defaultPadding;
}
}
_dottedBorder.Height = content.ActualHeight+defaultPadding;
_dottedBorder.Width = content.ActualWidth + defaultPadding;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}
Related
i have created an android application using xamarin.android. the application has a recyclerview that contains a spinner. what i want is when the user selects an item from the spinner, i need to change the value of the corresponding column and row in the datatable and i need the new value to be displayed in the spinner in the recyclerview in the row where the spinner value is selected. the problem is that whenever a value is selected, when another row is clicked, the old value of the spinner is displayed. i tried a lot of ways like the code in the following link: https://www.codeproject.com/articles/1033283/android-recycler-view-with-spinner-item-change-sel, but it didn't work. this is my code:
public class recyclerview_viewholder : RecyclerView.ViewHolder
{
public TextView rownbr, laborname;
public EditText overtime;
public LinearLayout linearLayout;
public Spinner days;
public recyclerview_viewholder(View itemView, Action<int> listener)
: base(itemView)
{
rownbr = itemView.FindViewById<TextView>(Resource.Id.rownbr);
laborname = itemView.FindViewById<TextView>(Resource.Id.laborname);
days = itemView.FindViewById<Spinner>(Resource.Id.days);
overtime = itemView.FindViewById<EditText>(Resource.Id.overtime);
linearLayout = itemView.FindViewById<LinearLayout>(Resource.Id.linearLayout);
itemView.Click += (sender, e) => listener(base.LayoutPosition);
}
public class recyclerviewAdapter : RecyclerView.Adapter
{
// Event handler for item clicks:
public event EventHandler<int> ItemClick;
// public event EventHandler<AdapterView.ItemSelectedEventArgs> SpinnerItemSelectionChanged;
public static DataTable summary_Requests = new DataTable();
//Context context;
public readonly new_schedule context;
public static int selected_pos = -1;
RecyclerView recyclerView;
FloatingActionButton delete;
public recyclerviewAdapter(new_schedule context, DataTable sum_req, RecyclerView recyclerView)
{
this.context = context;
summary_Requests = sum_req;
this.recyclerView = recyclerView;
}
public override RecyclerView.ViewHolder
OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).
Inflate(Resource.Layout.recycler_view_new_schedule_data, parent, false);
recyclerview_viewholder vh = new recyclerview_viewholder(itemView, OnClick);
vh.days.ItemSelected += (sender, e) =>
{
Spinner spinner = (Spinner)sender;
int position = Convert.ToInt32(spinner.Tag);
summary_Requests.Rows[position]["dayNbr"] = Convert.ToDecimal(spinner.GetItemAtPosition(e.Position).ToString());
};
vh.overtime.TextChanged += (sender, e) =>
{
if (vh.overtime.Text != "")
try
{
int position = vh.LayoutPosition;
summary_Requests.Rows[position]["overtimeHours"] = Convert.ToInt32(vh.overtime.Text);
user.zero_val = "Not_exist";
}
catch (System.FormatException exp)
{
var icon = AppCompatResources.GetDrawable(context.Context, Resource.Drawable.error_ic);
icon.SetBounds(0, 0, 50, 50);
vh.overtime.SetError("unit must be integer not decimal", icon);
user.zero_val = "exits";
}
else if (vh.overtime.Text == "")
{
var icon = AppCompatResources.GetDrawable(context.Context, Resource.Drawable.error_ic);
icon.SetBounds(0, 0, 50, 50);
vh.overtime.SetError("value can not be empty", icon);
user.zero_val = "exits";
}
};
return vh;
}
public override void
OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
recyclerview_viewholder vh = holder as recyclerview_viewholder;
vh.rownbr.Text = summary_Requests.Rows[position]["rowNumber"].ToString();
vh.laborname.Text = summary_Requests.Rows[position]["laborerName"].ToString();
List<decimal> days_data = new List<decimal>();
days_data.Add((decimal)0.5);
days_data.Add((decimal)1);
var adapter = new ArrayAdapter(this.context.Context, Android.Resource.Layout.SimpleSpinnerItem, days_data);
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
vh.days.Tag = position;
vh.days.Adapter = adapter;
vh.days.SetSelection(1);
vh.overtime.Text = summary_Requests.Rows[position]["overtimeHours"].ToString();
if (selected_pos == position)
vh.ItemView.SetBackgroundColor(Color.ParseColor("#4fa5d5"));
else
vh.ItemView.SetBackgroundColor(Color.LightGray);
vh.ItemView.Click += (sender, e) =>
{
int pos = vh.LayoutPosition;
user.del_pos = position;
selected_pos = position;
NotifyDataSetChanged();
//fill global variables that need to be passed to detail fragment
};
//delete.Click += delegate
//{
// vh.days.Enabled = false;
//};
}
public DataTable get_dt_final()
{
DataTable final_dt = summary_Requests.Copy();
return final_dt;
}
public override long GetItemId(int position)
{
return position;
}
public void deleteItem(int index)
{
summary_Requests.Rows.RemoveAt(index);
NotifyItemRemoved(index);
}
public override int ItemCount
{
get { return summary_Requests.Rows.Count; }
}
// Raise an event when the item-click takes place:
void OnClick(int position)
{
if (ItemClick != null)
ItemClick(this, position);
// user.req_pos = position;
}
}
}
}
I read the article that you provide, you need to do two things when you change spinner value, firstly, you need to change vegeList's itemPosition quantity by SpinnerItemSelectionChangedEvent, then you need to update TotalAmount in OnBindViewHolder
private void SpinnerItemSelectionChangedEvent(object sender, AdapterView.ItemSelectedEventArgs e)
{
Spinner spinner = (Spinner)sender;
var itemPosition = Convert.ToInt32(spinner.Tag);
//Update the view by Total Amount, after spinner value is been selected.
var currentquantity = vegeList[itemPosition].Quantity;
var selectedQuantity = Convert.ToInt32(spinner.GetItemAtPosition(e.Position).ToString());
if (currentquantity != selectedQuantity)
{
vegeList[itemPosition].Quantity = selectedQuantity;
Madapter.NotifyItemChanged(itemPosition);
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
var item = Items[position];
var vh = holder as VegeViewHolder;
var spinnerPos = 0;
var adapter = new ArrayAdapter<String>(Context, Android.Resource.Layout.SimpleSpinnerItem, _quantity);
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
vh.Name.Text = item.Name;
vh.Price.Text = string.Format("Price: ${0}", item.Price);
vh.ItemView.Tag = position;
if (item.Quantity > 0)
{
spinnerPos = adapter.GetPosition(item.Quantity.ToString());
vh.TotalAmount.Text = string.Format("${0}", item.Price * item.Quantity);
}
else
{
vh.TotalAmount.Text = "";
}
vh.Quantity.Tag = position; //keep reference to list view row position
vh.Quantity.Adapter = adapter;
vh.Quantity.SetSelection(spinnerPos);
vh.Image.SetImageResource(item.ImageId);
}
I used ItemAppearing and ItemDisappearing events but it is not working as per my requirement (it is working fine in iOS but not in android) and I created custom render for listview for listview scroll I failed to do that. Can anyone please help me out.
private void scheduleservicelist_itemappearing(object sender, xamarin.forms.itemvisibilityeventargs e)
{
var currentitem = e.item as mymodel;
if (viewmodel.mylistlist[0].id == currentitem.id)
{
headerlayout.isvisible = true; headinggrid.margin = new thickness(0,-70, 0, 0);
}
}
private void scheduleservicelist_itemdisappearing(object sender, itemvisibilityeventargs e)
{
var currentitem = e.item as mymodel;
if (viewmodel.mylistlist[0].id == currentitem.id)
{
headerlayout.isvisible = false; headinggrid.margin = new thickness(0, 0, 0, 0);
}
}
private void ScheduleServiceListView_Scrolled(object sender, ScrolledEventArgs e)
{
double scrollposition = e.ScrollY; if (scrollposition > previousScrollposition)
{
isScrollUp = true; isScrollDown = false;
}
else if(scrollposition < previousScrollposition)
{
isScrollDown => true; isScrollUp = false;
}
else
{
if (isScrollUp)
{
isScrollUp =true; isScrollDown = false;
}
else
{
isScrollDown = true; isScrollUp = false;
}
scrollposition = 0;
}
if (isScrollUp )
{
HeaderLayout.IsVisible = false;
HeadingGrid.Margin = new Thickness(0, 0, 0, 0);
HeadingGrid.VerticalOptions = LayoutOptions.Start;
}
else
{
HeaderLayout.IsVisible = true;
HeadingGrid.Margin = new Thickness(0, -70, 0, 0);
}
previousScrollposition = scrollposition;
}
In code behind this is done by
ActivityList.ScrollIntoView(ActivityList.SelectedItem);
when you come back from the detailpage so that when you return from the detailpage you don't have to start from the top of the ListView.
There are a few examples to scroll to the end of a ListView but not to the SelectedItem.
But how is this done in MVVM? Creating a Behavior with Behavior SDK? And how?
I've done this with an attached-property (behavior). This behavior is in a class called DataGridExtensions and looks like:
public static readonly DependencyProperty ScrollSelectionIntoViewProperty = DependencyProperty.RegisterAttached(
"ScrollSelectionIntoView", typeof(bool), typeof(DataGridExtensions), new PropertyMetadata(false, ScrollSelectionIntoViewChanged));
private static void ScrollSelectionIntoViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = d as DataGrid;
if (dataGrid == null)
return;
if (e.NewValue is bool && (bool)e.NewValue)
dataGrid.SelectionChanged += DataGridOnSelectionChanged;
else
dataGrid.SelectionChanged -= DataGridOnSelectionChanged;
}
private static void DataGridOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems == null || e.AddedItems.Count == 0)
return;
DataGrid dataGrid = sender as DataGrid;
if (dataGrid == null)
return;
ScrollViewer scrollViewer = UIHelper.FindChildren<ScrollViewer>(dataGrid).FirstOrDefault();
if (scrollViewer != null)
{
dataGrid.ScrollIntoView(e.AddedItems[0]);
}
}
public static void SetScrollSelectionIntoView(DependencyObject element, bool value)
{
element.SetValue(ScrollSelectionIntoViewProperty, value);
}
public static bool GetScrollSelectionIntoView(DependencyObject element)
{
return (bool)element.GetValue(ScrollSelectionIntoViewProperty);
}
The code of UIHelper.FindChildren is:
public static IList<T> FindChildren<T>(DependencyObject element) where T : FrameworkElement
{
List<T> retval = new List<T>();
for (int counter = 0; counter < VisualTreeHelper.GetChildrenCount(element); counter++)
{
FrameworkElement toadd = VisualTreeHelper.GetChild(element, counter) as FrameworkElement;
if (toadd != null)
{
T correctlyTyped = toadd as T;
if (correctlyTyped != null)
{
retval.Add(correctlyTyped);
}
else
{
retval.AddRange(FindChildren<T>(toadd));
}
}
}
return retval;
}
I am trying to find a solution to allow a Hub to pan with the mouse when its reaches the left or right boundary. I have implemented the code below which i have gleaned from various sources.
` private void theHubPointerMoved(object sender, PointerRoutedEventArgs e)
{ Windows.UI.Xaml.Input.Pointer ptr = e.Pointer;
if (ptr.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
Windows.UI.Input.PointerPoint ptrPt = e.GetCurrentPoint(null);
if (ptrPt.Position.X < this.ActualWidth - 20)
if (ptrPt.Position.X > 20)
{
//Do the SCROLLING HERE
var xcord = Math.Round(ptrPt.Position.X, 2);
var ycord = Math.Round(ptrPt.Position.Y, 2);
}
}
e.Handled = true;
}`
So it is relativley easy to see when the mouse is at the screen edge. I thought it would be easy to simply use the MyHub.ScrollViewer.ScrollToHorizontalOffset(xcord); but the Hub Scrollviewer doesnt expose this ScrollToHorizontalOffset function.
Can anyone assist?
Thanks.
Oh, it's exposed. If you can handle digging for it. Here's how:
http://xaml.codeplex.com/SourceControl/latest#Blog/201401-ScrollHub/MainPage.xaml.cs
In the example below, it is scrolling to a specific hub section. But you should be able to easily adapt it to your specific needs, I hope.
private void ScollHubToSection(Hub hub, HubSection section)
{
var visual = section.TransformToVisual(this.MyHub);
var point = visual.TransformPoint(new Point(0, 0));
var viewer = Helpers.FindChild<ScrollViewer>(hub, "ScrollViewer");
viewer.ChangeView(point.X, null, null);
}
Using this:
public class Helpers
{
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
T childType = child as T;
if (childType == null)
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
Best of luck!
Not able to set image source Uri on find Object.
Stackpanel contain two children Textbox and image control.
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = (TextBox)sender;
textBox.Style = Application.Current.Resources["TextBoxNormal"] as Style;
textBox.FontSize = 15;
textBox.Foreground = new SolidColorBrush(Colors.Gray);
var stackpanel = textBox.Parent as StackPanel;
if (stackpanel == null)return;
var img = stackpanel.Children.Where(a => a is Image).FirstOrDefault();
if (textBox.Text != "")
{
//I was trying set Uri as mention below, but there is Nothing like "Image.Source"
//image.Source = new BitmapImage(new Uri("/Images/Others/TickRight.png", UriKind.RelativeOrAbsolute));
}
So I Would suggest Trouble shooting here.
if (textBox.Text != "")
{
BitmapImage picture = new BitmapImage(new Uri("/Images/Others/TickRight.png", UriKind.RelativeOrAbsolute));
picture.ImageFailed += (o, e) => System.Threading.SynchronizationContext.Current.Send((oo) => System.Windows.Browser.HtmlPage.Window.Alert("Image failed: " + e.ErrorException), null);
picture.ImageOpened += (o, e) => System.Threading.SynchronizationContext.Current.Send((oo) => System.Windows.Browser.HtmlPage.Window.Alert("Image opened: " + e.OriginalSource), null);
image.Source = picture;
}
//BANG.. your error should be naked!
You need cast img as Image
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
var stackpanel = textBox.Parent as StackPanel;
if (stackpanel == null)return;
var img = stackpanel.Children.Where(a => a is Image).FirstOrDefault() as Image;
}