I have added FlowListView in my project. As mention in the FAQ I am facing the entire row highlighting issue when tapped one item in windows, no such issue in android. I have added the custom renderers like below:
In Main Project:
using DLToolkit.Forms.Controls;
namespace Mynamespace
{
public class CustomFlowListView : FlowListView
{
}
}
In UWP:
using Listpm;
using Listpm.UWP;
using Xamarin.Forms;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(CustomFlowListView), typeof(CustomListViewRenderer))]
namespace Listpm.UWP
{
class CustomListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (List != null)
List.SelectionMode = Windows.UI.Xaml.Controls.ListViewSelectionMode.None;
}
}
}
In xaml added <local:CustomFlowListView> instead of <flv:FlowListView>.
<local:CustomFlowListView
FlowColumnCount="2"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="200"
FlowItemsSource="{Binding AllItems}">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<StackLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Image/>
</StackLayout>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</local:CustomFlowListView>
Are there any other changes instead of this for solving this issue?
How can I disable entire row highlighting when tapped?
You also need to add List.IsItemClickEnabled = false. And it will not effect FlowItemTapped event.
protected override void
OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
{
base.OnElementChanged(e);
if (List != null)
List.SelectionMode = Windows.UI.Xaml.Controls.ListViewSelectionMode.None;
List.IsItemClickEnabled = false;
}
Related
I am new to Uno and I have been following the frame navigation tutorial. I noticed that when the frame navigates the entire window changes. This is good but not optimal. Is there a way in Uno to have a Main Layout, like you would see in a ASP.Net MVC project? I would rather not implement the navigation menu on each page.
To extend on #matfillion's answer, if NavigationView doesn't suit your needs, you can easily roll your own navigation shell whilst leveraging the built-in frame navigation. There's no requirement for Frame to be the top-level control in your application.
Here's an ultra-simple example, to illustrate the principle. The navigation list will stay visible at the top whilst navigating between pages.
Shell.xaml:
<UserControl x:Class="UnoTestbed44.Shell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListView x:Name="NavigationList"
Background="LightGray"
ItemsSource="{x:Bind Pages}"
Grid.Row="0"
DisplayMemberPath="Label"
SelectionChanged="NavigationList_SelectionChanged">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<Frame x:Name="MainFrame"
Grid.Row="1" />
</Grid>
</UserControl>
Shell.xaml.cs:
using System;
using System.Linq;
using Windows.UI.Xaml.Controls;
namespace UnoTestbed44
{
public sealed partial class Shell : UserControl
{
public NavigationItem[] Pages { get; } = new[] {
new NavigationItem {Label = "First page", PageType = typeof(Page1)},
new NavigationItem {Label = "Second page", PageType = typeof(Page2)},
};
public Shell()
{
this.InitializeComponent();
}
private void NavigationList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.FirstOrDefault() is NavigationItem navigationItem)
{
MainFrame.Navigate(navigationItem.PageType);
}
}
public class NavigationItem
{
public string Label { get; set; }
public Type PageType { get; set; }
}
}
}
Override OnLaunched() in App.xaml.cs:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if NET5_0 && WINDOWS
_window = new Window();
_window.Activate();
#else
_window = Windows.UI.Xaml.Window.Current;
#endif
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (_window.Content == null)
{
_window.Content = new Shell();
}
#if !(NET5_0 && WINDOWS)
if (e.PrelaunchActivated == false)
#endif
{
// Ensure the current window is active
_window.Activate();
}
}
While not exactly what you are looking for, I believe the NavigationView control is your closest bet. You can disable CompactView and obtain something like what is showcased in UnoGallery.
How to change the color of searchbar icon from xaml, I want to change the cancel and search icon color of a search bar in xamarin forms application.How to implement this. Please help on this
As adamm said, you can modify the "cancel button color" via CancelButtonColor.
Similarly, if you want to implement a custom SearchBar in iOS, you can also create a custom renderer for it.
For UISearchBar, you can modify the color of the icon via SearchTextField.LeftView.TintColor.
[assembly: ExportRenderer(typeof(MySearchBar), typeof(MySearchBarRenderer))]
namespace searchbar.iOS
{
public class MySearchBarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BackgroundColor = UIColor.Yellow;
UISearchBar searchbar = Control as UISearchBar;
searchbar.SearchTextField.LeftView.TintColor = UIColor.Orange;
// UPDATE
var clearButton = searchbar.SearchTextField.ValueForKey((Foundation.NSString)"clearButton") as UIButton;
//clearButton.SetTitleColor(UIColor.Blue, UIControlState.Normal);
//clearButton.TintColor = UIColor.Orange;
clearButton.SetImage(UIImage.FromBundle("CloseIcon.png"), UIControlState.Normal);
}
}
}
}
Cancel button color can be change by setting CancelButtonColor:
<SearchBar Placeholder="Search items..."
CancelButtonColor="Orange"
PlaceholderColor="Orange"
TextColor="Orange"
TextTransform="Lowercase"
HorizontalTextAlignment="Center"
FontSize="Medium"
FontAttributes="Italic" />
For the icon color you need to use custom renderers.
For example, on Android you can create a new file (something like SearchBar.Droid.cs) and add this in it:
using Android.Content;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(Xamarin.Forms.SearchBar), typeof(MyApp.Renderers.SearchBarIconColorCustomRenderer))]
namespace MyApp.Renderers
{
public class SearchBarIconColorCustomRenderer : SearchBarRenderer
{
public SearchBarIconColorCustomRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
var icon = Control?.FindViewById(Context.Resources.GetIdentifier("android:id/search_mag_icon", null, null));
(icon as ImageView)?.SetColorFilter(Color.Orange.ToAndroid());
}
}
}
Edit:
For iOS, try something like this (I didn't test it):
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(Xamarin.Forms.SearchBar), typeof(MyApp.iOS.Renderers.iOSSearchBarIconColorCustomRenderer))]
namespace MyApp.iOS.Renderers
{
public class iOSSearchBarIconColorCustomRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var searchbar = (UISearchBar)Control;
searchbar.TintColor = UIColor.Orange;
}
}
}
}
On Android, when using an Editor control straight out of the box it is clear where the text/numeric data should be entered:
On iOS it is not so obvious and I find myself having to guess where to press to bring the control in to focus:
The code shared across the controls:
<Editor Grid.Row="1" Grid.Column="1"
Text="SomeTextHere"
VerticalOptions="Center"
Keyboard="Numeric"
HorizontalOptions="CenterAndExpand"
WidthRequest="68"
MinimumWidthRequest="68"
/>
I'm not averse to writing a custom control if I have to, but is there an easier way?
Please note that I don't want to use placeholder text.
You can use CustomRenderer to implement it.
Solution1
You can set the border of the Editor in iOS .
using Foundation;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx.iOS;
[assembly:ExportRenderer(typeof(Editor),typeof(MyEditorRenderer))]
namespace xxx.iOS
{
public class MyEditorRenderer:EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.Layer.MasksToBounds = true;
Control.Layer.BorderWidth = 1.0f;
Control.Layer.BorderColor = UIColor.Black.CGColor;
}
}
}
}
Solution2
If you do want to it display like in Android (only an under line)
using Foundation;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx.iOS;
[assembly:ExportRenderer(typeof(Editor),typeof(MyEditorRenderer))]
namespace xxx.iOS
{
public class MyEditorRenderer:EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
UIView lineView = new UIView() {
Frame = new CGRect(0,Element.HeightRequest-1,Element.WidthRequest, 1),
BackgroundColor = UIColor.Black,
};
Control.AddSubview(lineView);
}
}
}
}
And you need to set the HeightRequest and WidthRequest in Xaml .
Please consider the following issue.
In my Xamarin.Forms app I have a custom render for UWP that allows for a button to have two lines, and be centralised.
The buttons in questions are items in a Listview that are bound to objects. When they are initially generated, they display correctly with both lines of text in the center of the button, however if I update the text, it updates, but seems to bypass the custom renders "be in the center" code.
Please see the below code snippets and images to explain the situation further.
Custom Render
[assembly: ExportRenderer(typeof(TwoLinedButton), typeof(TwoLinedButtonUWP))]
namespace aphiresawesomeproject.UWP
{
public class TwoLinedButtonUWP : ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement.Text != null)
{
var textBlock = new Windows.UI.Xaml.Controls.TextBlock
{
Text = e.NewElement.Text,
TextAlignment = Windows.UI.Xaml.TextAlignment.Center,
TextWrapping = TextWrapping.WrapWholeWords
};
Control.Content = textBlock;
}
}
}
}
XAML
<ListView x:Name="AphiresListView" CachingStrategy="RecycleElement" ItemsSource="{Binding ListViewItems}" Margin="0,20,0,0" RowHeight="130" SeparatorVisibility="None" VerticalOptions="FillAndExpand" Grid.Column="1" Grid.Row ="3" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:TwoLinedButton Command="{Binding ClickedCommand}" Margin="5,10,5,10" HorizontalOptions ="FillAndExpand" BackgroundColor="{Binding color_hex}" Grid.Column="1" TextColor="{StaticResource LightTextColor}" FontSize="Medium" Text="{Binding problem_title}"></local:TwoLinedButton>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Update in Viewmodel
foreach (AphiresObject ViewItem in ListViewItems)
{
ViewItem.problem_title = ViewItem.problem_title.Replace("Line 2", "Updated Line 2");
}
Before
After
I think all you need to do is override OnElementPropertyChanged in your renderer and set the textBlock properties again when your text property changes.
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == TwoLinedButton.TextProperty.PropertyName)
{
//Set text block properties
}
}
You may also need to tell the view to re-render itself.
iOS: this.SetNeedsDisplay();
Android: this.Invalidate();
There are a few good examples already of how to create a "custom control" by -
Deriving a Class from View or an existing built-in control and then creating a custom renderer for it per platform.
http://blog.xamarin.com/using-custom-controls-in-xamarin.forms-on-android/
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/
I want to create a "compound custom control OR usercontrol" which contains multiple elements which are defined in XAML (in the shared code), and then customised with a renderer (to say tweak the styling per platform).
Does anyone have an example of doing this please? A simple example with a view that has a bindable label and an entry box should be enough to show the main principles.
Here is what I have so far -
Defined a ContentView to represent our usercontrols layout and contents.
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
with codebehind -
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView ()
{
InitializeComponent ();
}
// Not sure if I need this to access Entry ...
public Entry GetEntry ()
{
return MyEntry;
}
}
Add an Android Custom Renderer for that ContentView, how do I access and customise natively parts / controls of the ContentView?
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
// i.e. How could I get hold of EditText etc so I could natively customise its appearance? When you use a built in renderer like EntryRenderer you can use Control to access native control.
Console.WriteLine (newsContentView.GetLabel ().Text);
EditText ed = (EditText)newsContentView.GetEntry ().???
}
}
}
}
Just can't quite get the pieces together to work, the ContentView seems to render fine on page but cannot work out how to access its Child Native controls in the viewrenderer.
Be nice to also show how you can use Binding for the Label and Entry Text values.
I do not want to have to define a custom renderer for each single label / entry etc of the usercontrol.
Is this what you meant?
Some properties to access the Xamarin.Forms controls:
public partial class VisualNewsContentView : ContentView
{
public VisualNewsContentView()
{
InitializeComponent();
}
public Label Label
{
get
{
return MyLabel;
}
set
{
MyLabel = value;
}
}
public Entry Entry
{
get
{
return MyEntry;
}
set
{
MyEntry = value;
}
}
}
Some magic inside the Renderer to customize the controls on the page:
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: ViewRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
VisualNewsContentView newsContentView = newModel as VisualNewsContentView;
newsContentView.Label.Text = "It´s some kind of..";
newsContentView.Entry.Text = "MAGIC!";
newsContentView.Entry.BackgroundColor = Color.Blue;
newsContentView.Entry.RotationX = 180;
newsContentView.Entry.Focus();
}
}
}
}
EDIT:
I don't know if it's possible to map your controls from the XAML-page to native controls. You could add the controls which you want to customize natively # the renderer.
[assembly:ExportRenderer (typeof(VisualNewsContentView), typeof(VisualNewsRenderer))]
namespace News.Forms.Android
{
public class VisualNewsRenderer: NativeRenderer
{
public VisualNewsRenderer () { }
protected override void OnModelChanged (VisualElement oldModel, VisualElement newModel)
{
base.OnModelChanged (oldModel, newModel);
if (newModel != null) {
LinearLayout layout = new LinearLayout (Application.Context);
layout.Orientation = Orientation.Vertical;
TextView tv = new TextView (Application.Context);
tv.Ellipsize = TextUtils.TruncateAt.Middle;
tv.Text = "It´s some kind of..";
EditText et = new EditText (Application.Context);
et.SetTextColor (Graphics.Color.Chocolate);
et.Text = "MAGIC!";
layout.AddView (tv);
layout.AddView (et);
SetNativeControl (layout);
}
}
}
}
But like this you won't be using your ContentView.. I'm sorry, I have nothing better than this..
My solution for customizing compound user control is make a custom control for each control used in compound user control.
For example, which this control:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<StackLayout>
<Label x:Name="MyLabel" Text="Label"></Label>
<Entry x:Name="MyEntry" Text="Entry"></Entry>
</StackLayout>
</ContentView.Content>
</ContentView>
I will do something like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:CustomControls="clr-namespace:App.CustomControls;assembly=App" x:Class="News.Forms.VisualNewsContentView">
<ContentView.Content>
<CustomControls:StackLayout>
<CustomControls:Label x:Name="MyLabel" Text="Label"></CustomControls:Label>
<CustomControls:Entry x:Name="MyEntry" Text="Entry"></CustomControls:Entry>
</CustomControls:StackLayout>
</ContentView.Content>
</ContentView>
Example class for CustomControls:StackLayout is:
(in StackLayout.cs)
using Xamarin.Forms;
namespace App.CustomControls
{
public class StackLayout : Xamarin.Forms.StackLayout
{
}
}
(in StackLayoutRenderer.cs for android project)
[assembly: ExportRenderer(typeof(App.CustomControls.StackLayout), typeof(App.Droid.CustomRenderers.StackLayoutRenderer))]
namespace App.Droid.CustomRenderers.MapView
{
public class StackLayoutRenderer : ViewRenderer<StackLayout, Android.Widget.LinearLayout>
{
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
}
}
}