add 2 kb articles
This commit is contained in:
Родитель
7d917c24b8
Коммит
a815185b16
|
@ -0,0 +1,161 @@
|
|||
---
|
||||
title: Minor Ticks and Title in Gauges for Xamarin
|
||||
description: how to add minor ticks inside RadGauge for Xamarin
|
||||
type: how-to
|
||||
page_title: Add minor ticks and title to the Gauge for Xamarin
|
||||
slug: gauge-minor-ticks
|
||||
position:
|
||||
tags: gauge-minor-ticks-and-title
|
||||
ticketid: 1502506
|
||||
res_type: kb
|
||||
---
|
||||
|
||||
## Environment
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2021.1.119.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>Chart for Xamarin Cross-Platform</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
This article will show you how to add minor ticks and title to the RadGauge control. The solution can be created with a little clever use of existing indicators and some custom development.
|
||||
|
||||
![Gauge minor ticks and title](images/gauge-minor-ticks-title.png)
|
||||
|
||||
## Solution
|
||||
|
||||
1. Use [GaugeShapeIndicator]({%slug gauge-indicators%})
|
||||
|
||||
2. Draw the rectangle shape using [RadPathGeometry]({%slug path-structure%}). This is a very simple shape path just like you're familiar with on any platform that uses X,Y coordinates to draw a line. You will need to create one GaugeShapeIndicator for every square.
|
||||
|
||||
3. Create Custom Algorithm to draw the shapes.
|
||||
|
||||
Here is the RadGauge definition. The labels inside the stackLayout will be used for displaying a title for the Gauge control
|
||||
|
||||
```XAML
|
||||
<Grid x:Name="MyGaugeGrid" WidthRequest="400" HeightRequest="400" VerticalOptions="Start" HorizontalOptions="Center" Margin="50" >
|
||||
<telerikGauges:RadRadialGauge x:Name="gauge"
|
||||
Margin="10"
|
||||
StartAngle="225"
|
||||
SweepAngle="270">
|
||||
<telerikGauges:RadRadialGauge.Axis>
|
||||
<telerikGauges:GaugeLinearAxis Minimum="0" Maximum="100"
|
||||
ShowLabels="True"
|
||||
StrokeThickness="0"
|
||||
Step="10"
|
||||
/>
|
||||
</telerikGauges:RadRadialGauge.Axis>
|
||||
<telerikGauges:RadRadialGauge.Indicators>
|
||||
<telerikGauges:GaugeBarIndicator StartCap="Flat"
|
||||
EndCap="Flat"
|
||||
Fill="LightGray"
|
||||
Offset="3"
|
||||
Value="100" />
|
||||
<telerikGauges:GaugeBarIndicator StartCap="Flat"
|
||||
EndCap="Flat"
|
||||
Fill="Gold"
|
||||
Offset="3"
|
||||
Value="{Binding OtherValue}" />
|
||||
</telerikGauges:RadRadialGauge.Indicators>
|
||||
</telerikGauges:RadRadialGauge>
|
||||
|
||||
<!-- for the Gauge Title-->
|
||||
<StackLayout HorizontalOptions="Center" VerticalOptions="Center" Margin="0,40,0,0" Spacing="0">
|
||||
<Label x:Name="OtherValueLabel"
|
||||
Text="{Binding OtherValue, StringFormat='{0}%'}"
|
||||
TextColor="Gold"
|
||||
HorizontalTextAlignment="Center"
|
||||
FontSize="22" />
|
||||
<Label Text="Other Value"
|
||||
TextColor="LightGray"
|
||||
HorizontalTextAlignment="Center"
|
||||
FontSize="8" />
|
||||
<Label x:Name="Label"
|
||||
TextColor="GreenYellow"
|
||||
Text="{Binding MyPoints, StringFormat='{0}%'}"
|
||||
HorizontalTextAlignment="Center"
|
||||
FontSize="22" />
|
||||
<Label Text="My Points"
|
||||
HorizontalTextAlignment="Center"
|
||||
FontSize="8"
|
||||
TextColor="LightGray" />
|
||||
</StackLayout>
|
||||
</Grid>
|
||||
```
|
||||
|
||||
and the code behind and the custom algorithm in action
|
||||
|
||||
```C#
|
||||
public partial class MainPage : ContentPage
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.BindingContext = new MainViewModel();
|
||||
}
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
|
||||
var avgPercentage = (BindingContext as MainViewModel).MyPoints;
|
||||
|
||||
DrawRectangleIndicators(avgPercentage);
|
||||
}
|
||||
|
||||
private void DrawRectangleIndicators(double totalValue)
|
||||
{
|
||||
for (int i = 0; i < totalValue; i++)
|
||||
{
|
||||
// Draw an indicator at every 3rd slot
|
||||
if (i % 3 == 0)
|
||||
{
|
||||
gauge.Indicators.Add(CreateGaugeShapeIndicator(i));
|
||||
}
|
||||
}
|
||||
|
||||
// draw final indicator to represent the total value
|
||||
gauge.Indicators.Add(CreateGaugeShapeIndicator(totalValue));
|
||||
}
|
||||
|
||||
private GaugeShapeIndicator CreateGaugeShapeIndicator(double indicatorValue)
|
||||
{
|
||||
var pathGeometry = new RadPathGeometry();
|
||||
var pathFigure = new RadPathFigure { StartPoint = new Point(1, 0.2) };
|
||||
pathFigure.Segments.Add(new RadLineSegment { Point = new Point(0, 0.2) });
|
||||
pathFigure.Segments.Add(new RadLineSegment { Point = new Point(0, 0.8) });
|
||||
pathFigure.Segments.Add(new RadLineSegment { Point = new Point(1, 0.8) });
|
||||
pathGeometry.Figures.Add(pathFigure);
|
||||
|
||||
return new GaugeShapeIndicator
|
||||
{
|
||||
Value = indicatorValue,
|
||||
Fill = Color.YellowGreen,
|
||||
Size = 5,
|
||||
Offset = 30,
|
||||
Position = GaugeElementPosition.Start,
|
||||
Shape = pathGeometry
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class MainViewModel
|
||||
{
|
||||
public MainViewModel()
|
||||
{
|
||||
}
|
||||
public double OtherValue { get; set; } = 68;
|
||||
public double MyPoints { get; set; } = 72;
|
||||
}
|
||||
```
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 12 KiB |
|
@ -0,0 +1,341 @@
|
|||
---
|
||||
title: TreeView Disable horizontal scroll caused by long item names
|
||||
description: This article will show you how to disable the horizontal scroll inside the TreeView control.
|
||||
type: how-to
|
||||
page_title: Disable TreeView hrizontal scroll caused with items with long text
|
||||
slug: treeview-disable-horizontal-scroll
|
||||
position:
|
||||
tags: treeview, scrolling, horizontal scroll, long text, xamarin, xamarin.forms
|
||||
ticketid: 1503952
|
||||
res_type: kb
|
||||
---
|
||||
|
||||
## Environment
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Product Version</td>
|
||||
<td>2021.1.119.1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Product</td>
|
||||
<td>TreeView for Xamarin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
For this purpose, we will need to implement a custom renderer for android and for iOS.
|
||||
|
||||
## Solution
|
||||
|
||||
Here is a sample TreeView definition:
|
||||
|
||||
```XAML
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<telerikTreeView:LevelToMarginConverter x:Key="levelToMarginConverter" />
|
||||
|
||||
<DataTemplate x:Key="CustomControlTemplate">
|
||||
<StackLayout Orientation="Horizontal"
|
||||
Margin="{Binding Path=Level, Converter={StaticResource levelToMarginConverter}}">
|
||||
<StackLayout.HeightRequest>
|
||||
<OnPlatform x:TypeArguments="x:Double">
|
||||
<On Platform="iOS" Value="44"></On>
|
||||
<On Platform="Android" Value="40"></On>
|
||||
<On Platform="UWP" Value="40"></On>
|
||||
</OnPlatform>
|
||||
</StackLayout.HeightRequest>
|
||||
<telerikTreeView:ExpandCollapseIndicator FontSize="Medium"
|
||||
WidthRequest="10"
|
||||
Margin="15,0"
|
||||
VerticalTextAlignment="Center"
|
||||
IsLoading="{Binding Path=IsLoading}"
|
||||
IsLoadOnDemandEnabled="{Binding Path=IsLoadOnDemandEnabled}"
|
||||
IsExpanded="{Binding Path=IsExpanded}"
|
||||
IsLeaf="{Binding Path=IsLeaf}"/>
|
||||
<telerikPrimitives:RadCheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"
|
||||
IsVisible="{Binding Path=IsCheckBoxVisible}"
|
||||
VerticalOptions="Center"/>
|
||||
<telerikTreeView:ItemText Text="{Binding Path=Header}"
|
||||
VerticalTextAlignment="Center"
|
||||
MaxLines="1"
|
||||
LineBreakMode="TailTruncation"/>
|
||||
</StackLayout>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<Grid>
|
||||
<telerikDataControls:RadTreeView x:Name="treeView" ItemsSource="{Binding Source}">
|
||||
<telerikDataControls:TreeViewDescriptor DisplayMemberPath="Name"
|
||||
ItemsSourcePath="Children"
|
||||
ItemTemplate="{StaticResource CustomControlTemplate}"
|
||||
TargetType="{x:Type local:Item}" />
|
||||
</telerikDataControls:RadTreeView>
|
||||
</Grid>
|
||||
```
|
||||
|
||||
and the used ViewModel
|
||||
|
||||
```C#
|
||||
public class Item
|
||||
{
|
||||
public Item(string name)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Children = new ObservableCollection<Item>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public IList<Item> Children { get; set; }
|
||||
}
|
||||
|
||||
public class ViewModel
|
||||
{
|
||||
public ViewModel()
|
||||
{
|
||||
Source = new ObservableCollection<Item>();
|
||||
Source.Add(new Item("My Documents")
|
||||
{
|
||||
Children = new List<Item>()
|
||||
{
|
||||
new Item("Xamarin Projects")
|
||||
{
|
||||
Children = new ObservableCollection<Item>()
|
||||
{
|
||||
new Item("TreeView Examples"),
|
||||
new Item("Calendar & Scheduling QSF")
|
||||
}
|
||||
},
|
||||
new Item("Documentation Drafts")
|
||||
}
|
||||
});
|
||||
Source.Add(new Item("Shared Documents")
|
||||
{
|
||||
Children = new List<Item>()
|
||||
{
|
||||
new Item("Reports")
|
||||
{
|
||||
Children = new List<Item>()
|
||||
{
|
||||
new Item("Long text text text text text text text text text text text text text text end"),
|
||||
new Item("November"),
|
||||
new Item("December")
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
public ObservableCollection<Item> Source { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
then the BindingContext set
|
||||
|
||||
```C#
|
||||
this.BindingContext = new ViewModel();
|
||||
```
|
||||
|
||||
### Custom Renderer for Android
|
||||
|
||||
Custom Renderer implementation on Android
|
||||
|
||||
```C#
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Android.Content;
|
||||
using AndroidX.RecyclerView.Widget;
|
||||
using RadTreeViewXF.Droid;
|
||||
using Telerik.XamarinForms.DataControls;
|
||||
using Telerik.XamarinForms.DataControls.TreeView;
|
||||
using Telerik.XamarinForms.DataControlsRenderer.Android;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AndroidViews = Android.Views;
|
||||
|
||||
[assembly: ExportRenderer(typeof(RadTreeView), typeof(CustomTreeViewRenderer))]
|
||||
namespace RadTreeViewXF.Droid
|
||||
{
|
||||
public class CustomTreeViewRenderer : TreeViewRenderer
|
||||
{
|
||||
public CustomTreeViewRenderer(Context context)
|
||||
: base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<RadTreeView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
var nativeTreeView = this.Control;
|
||||
if (nativeTreeView != null)
|
||||
{
|
||||
Registrar.Registered.Register(typeof(TreeViewTemplateCell), typeof(CustomTreeViewTemplateCellRenderer));
|
||||
nativeTreeView.SetLayoutManager(new LinearLayoutManager(this.Context));
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTreeViewTemplateCellRenderer : CellRenderer
|
||||
{
|
||||
protected override AndroidViews.View GetCellCore(Cell item, AndroidViews.View convertView, AndroidViews.ViewGroup parent, Context context)
|
||||
{
|
||||
var viewCell = (ViewCell)item;
|
||||
|
||||
IVisualElementRenderer renderer = Platform.GetRenderer(viewCell.View);
|
||||
if (renderer == null || renderer.Element == null)
|
||||
{
|
||||
renderer = Platform.CreateRendererWithContext(viewCell.View, context);
|
||||
Platform.SetRenderer(viewCell.View, renderer);
|
||||
}
|
||||
|
||||
return new TreeViewTemplateCellContainer(context, renderer, viewCell);
|
||||
}
|
||||
}
|
||||
|
||||
class TreeViewTemplateCellContainer : FormsViewGroup
|
||||
{
|
||||
private static Type invalidationEventArgsType;
|
||||
private static PropertyInfo triggerProperty;
|
||||
|
||||
protected readonly ViewCell viewCell;
|
||||
protected readonly IVisualElementRenderer view;
|
||||
private MethodInfo invalidateMeasureMethod;
|
||||
|
||||
public TreeViewTemplateCellContainer(Context context, IVisualElementRenderer view, ViewCell viewCell)
|
||||
: base(context)
|
||||
{
|
||||
this.viewCell = viewCell;
|
||||
this.view = view;
|
||||
this.AddView(view.View);
|
||||
|
||||
this.viewCell.View.MeasureInvalidated += this.OnMeasureInvalidated;
|
||||
this.invalidateMeasureMethod = this.view.Element.GetType().GetMethod("InvalidateMeasure", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new System.Type[] { }, new ParameterModifier[] { });
|
||||
}
|
||||
|
||||
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
var treeView = (RadExtendedListView)this.Parent;
|
||||
var width = treeView.Width;
|
||||
this.invalidateMeasureMethod.Invoke(this.view.Element, new object[] { });
|
||||
|
||||
var sizeRequest = this.view.Element.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins);
|
||||
|
||||
var height = (int)this.Context.ToPixels(this.viewCell.Height > 0 ? this.viewCell.Height : sizeRequest.Request.Height);
|
||||
this.SetMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
|
||||
{
|
||||
var context = base.Context;
|
||||
var width = context.FromPixels(right - left);
|
||||
var height = context.FromPixels(bottom - top);
|
||||
|
||||
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion(this.view.Element, new Rectangle(0, 0, width, height));
|
||||
this.view.UpdateLayout();
|
||||
}
|
||||
|
||||
private void OnMeasureInvalidated(object sender, System.EventArgs e)
|
||||
{
|
||||
var trigger = TryGetInvalidationTrigger(e);
|
||||
if (trigger.HasValue && trigger.Value.HasFlag(InvalidationTrigger.SizeRequestChanged) ||
|
||||
trigger.Value.HasFlag(InvalidationTrigger.MarginChanged) ||
|
||||
trigger.Value.HasFlag(InvalidationTrigger.MeasureChanged))
|
||||
{
|
||||
this.RequestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (this.viewCell != null && this.viewCell.View != null)
|
||||
{
|
||||
this.viewCell.View.MeasureInvalidated -= this.OnMeasureInvalidated;
|
||||
this.viewCell.View = null;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
internal static InvalidationTrigger? TryGetInvalidationTrigger(EventArgs e)
|
||||
{
|
||||
Type type = e.GetType();
|
||||
if (invalidationEventArgsType == null)
|
||||
{
|
||||
if (type.FullName == "Xamarin.Forms.InvalidationEventArgs")
|
||||
{
|
||||
invalidationEventArgsType = type;
|
||||
triggerProperty = type.GetRuntimeProperty("Trigger");
|
||||
}
|
||||
}
|
||||
|
||||
if (type != invalidationEventArgsType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
object propertyValue = triggerProperty.GetValue(e);
|
||||
InvalidationTrigger actualTrigger = (InvalidationTrigger)propertyValue;
|
||||
return actualTrigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Custom Renderer for iOS
|
||||
|
||||
Custom Renderer implementation on iOS
|
||||
|
||||
```C#
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using RadTreeViewXF.iOS;
|
||||
using Telerik.XamarinForms.DataControls;
|
||||
using Telerik.XamarinForms.DataControlsRenderer.iOS;
|
||||
using TelerikUI;
|
||||
using Xamarin.Forms;
|
||||
|
||||
[assembly: ExportRenderer(typeof(RadTreeView), typeof(CustomTreeViewRenderer))]
|
||||
namespace RadTreeViewXF.iOS
|
||||
{
|
||||
public class CustomTreeViewRenderer : TreeViewRenderer
|
||||
{
|
||||
protected override TKTreeViewListView CreateNativeControl()
|
||||
{
|
||||
return new CustomTKTreeViewListView();
|
||||
}
|
||||
|
||||
class CustomTKTreeViewListView : TKTreeViewListView
|
||||
{
|
||||
public override TKListViewLinearLayout CreateLayout()
|
||||
{
|
||||
return new CustomTreeViewLayout(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomTreeViewLayout : TreeViewLayout
|
||||
{
|
||||
TKListView listView;
|
||||
public CustomTreeViewLayout(TKListView listView)
|
||||
: base(listView)
|
||||
{
|
||||
this.listView = listView;
|
||||
}
|
||||
|
||||
public override CGSize GetItemSizeForIndexPath(NSIndexPath indexPath)
|
||||
{
|
||||
return this.Delegate.SizeForItem(this.listView, this, indexPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
Загрузка…
Ссылка в новой задаче