I'm currently trying to create a Button with custom color text when disabled. For this point i successfully did the job with a custom renderer.
But an unexpected side effect as came. Some button style are disapplying when passing on this specific state.
As you can see on the image above the button icon position is different and the cornerRadius property isn't applied anymore.
In the enable state with the custom button renderer i recover the cornerRadius property (actually i can resolve this problem setting each time the radius in the renderer, so isn't really a problem). The icon remain at the top and doesn't respect the ContentLayout margin property. The renderer i expect is the left button who is did with normal button component.
Here is the declaration of my control (i put the left button too to demonstrate the settings are the same:
<StackLayout Orientation="Horizontal" Margin="0,50,0,0">
<Button Text="Disponibilités de l'élève" BackgroundColor="{StaticResource Primary}" BorderColor="LightGray" BorderWidth="1" TextColor="White" FontAttributes="Bold" CornerRadius="10" ContentLayout="Top,25" WidthRequest="{Binding ButtonWidth}" HorizontalOptions="CenterAndExpand" Command="{Binding OpenMapCommand}">
<Button.ImageSource>
<FontImageSource FontFamily="FASolid" Color="White" Glyph="{x:Static fa:FontAwesomeIcons.CalendarDays}"/>
</Button.ImageSource>
</Button>
<!--<Button Text="Poser une option" BackgroundColor="{StaticResource Primary}" TextColor="White" BorderColor="LightGray" BorderWidth="1" FontAttributes="Bold" CornerRadius="10" ContentLayout="Top,25" WidthRequest="{Binding ButtonWidth}" HorizontalOptions="CenterAndExpand" Command="{Binding SubmitOptionCommand}">
<Button.ImageSource>
<FontImageSource FontFamily="FARegular" Color="White" Glyph="{x:Static fa:FontAwesomeIcons.CalendarPlus}"/>
</Button.ImageSource>
</Button>-->
<controls:DisableExtentButton Text="Poser une option" BackgroundColor="{StaticResource Primary}" DisabledBackgroundColor="LightGreen" TextColor="White" DisabledTextColor="Green" BorderColor="LightGray" BorderWidth="1" FontAttributes="Bold" CornerRadius="10" ContentLayout="Top,25" WidthRequest="{Binding ButtonWidth}" HorizontalOptions="CenterAndExpand" Command="{Binding SubmitOptionCommand}">
<Button.Triggers>
<DataTrigger TargetType="Button" Binding="{Binding OptionTaken}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="ImageSource">
<Setter.Value>
<FontImageSource FontFamily="FARegular" Color="Green" Glyph="{x:Static fa:FontAwesomeIcons.CalendarCheck}"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Button.Triggers>
<Button.ImageSource>
<FontImageSource FontFamily="FARegular" Color="White" Glyph="{x:Static fa:FontAwesomeIcons.CalendarPlus}"/>
</Button.ImageSource>
</controls:DisableExtentButton>
</StackLayout>
Here is the declaration of my custom Control:
public class DisableExtentButton : Button
{
public Color DisabledTextColor
{
get { return (Color)GetValue(DisabledTextColorProperty); }
set { SetValue(DisabledTextColorProperty, value); }
}
public Color DisabledBackgroundColor
{
get { return (Color)GetValue(DisabledBackgroundColorProperty); }
set { SetValue(DisabledBackgroundColorProperty, value); }
}
public static readonly BindableProperty DisabledTextColorProperty = BindableProperty.Create(nameof(DisabledTextColor), typeof(Color), typeof(DisableExtentButton), Color.Gray);
public static readonly BindableProperty DisabledBackgroundColorProperty = BindableProperty.Create(nameof(DisabledBackgroundColor), typeof(Color), typeof(DisableExtentButton), Color.DarkGray);
}
The android renderer:
public class DisableExtentButtonRenderer : ButtonRenderer
{
public DisableExtentButtonRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
if (Control != null)
SetColors();
base.OnElementChanged(e);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Button.IsEnabled))
SetColors();
base.OnElementPropertyChanged(sender, e);
}
private void SetColors()
{
var element = (DisableExtentButton)this.Element;
Control.SetTextColor(Element.IsEnabled ? Element.TextColor.ToAndroid() : element.DisabledTextColor.ToAndroid());
Control.SetBackgroundColor(Element.IsEnabled ? Element.BackgroundColor.ToAndroid() : element.DisabledBackgroundColor.ToAndroid());
}
}
I didn't successfully found why the ContentLayout property isn't applied correctly anymore and more for informational purpose why the corner radius is reseted when passing into OnElementPropertyChanged. If i redo the button without custom renderer it work as expected like the left button.
Related
I'm trying to change the background color or text color of a button in a collection view when clicked, this is what I have so far, but it is not working. I even tried to have the button as the root but the state still does not change
<CollectionView
ItemsSource="{Binding Suburbs}"
SelectionMode="None"
VerticalScrollBarVisibility="Never"
HorizontalScrollBarVisibility="Never">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" ItemSpacing="5" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
VerticalOptions="Start">
<Button
Padding="15"
CornerRadius="10"
BorderColor="Black"
BorderWidth="1"
TextColor="Black"
CommandParameter="{Binding .}"
Command="{Binding Source={x:Reference browse}, Path=BindingContext.CitySelectedCommand}"
BackgroundColor="Transparent"
Text="{Binding name}"
HeightRequest="30"
VerticalOptions="Start"
HorizontalOptions="FillAndExpand">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ColorStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="TextColor" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
``
Actually VisualStateGroup does work .
However the color only changes when you're pressing on the button , the color will change to origin color after you release the button .
Refer to Visual states in Xamarin.Forms.
If you want the button stays another color after clicking on it , you need to create a property in the model and bind it to the TextColor/BackgroundColor.
Xaml
TextColor="{Binding color}"
Command="{Binding command}"
Model
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string name { get; set; }
public Color _color;
public Color color {
get { return _color; }
set {
_color = value;
NotifyPropertyChanged();
}
}
public ICommand command { get; set; }
bool isClick = false;
public Model()
{
color = Color.Black;
command = new Command((obj)=> {
isClick = !isClick;
color = isClick ? Color.Red : Color.Black;
});
}
}
I've created a custom renderer for Frame to feel like CardView in Android it works fine on Android P but i've tested on API 21,22,23 it doesn't have any kind of effect. Here is my Android Renderer.
public class ShadowFrameRenderer : Xamarin.Forms.Platform.Android.AppCompat.FrameRenderer
{
public ShadowFrameRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
if (e.NewElement != null && e.NewElement is ShadowFrame)
{
Elevation = 30.0f;
TranslationZ = 0.0f;
SetZ(30f);
//this.SetBackgroundResource(Resource.Drawable.shadow);
//GradientDrawable drawable = (GradientDrawable)this.Background;
//drawable.SetColor(Android.Graphics.Color.ParseColor("#F0F0F0"));
}
UpdateElevation();
}
private void UpdateElevation()
{
//var materialFrame = (ShadowFrame)Element;
// we need to reset the StateListAnimator to override the setting of Elevation on touch down and release.
if(Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
Control.StateListAnimator = new Android.Animation.StateListAnimator();
// set the elevation manually
ViewCompat.SetElevation(this, 10);
ViewCompat.SetElevation(Control, 10);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Lollipop)
{
Control.Elevation = 10;
Control.CardElevation = 10;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
UpdateElevation();
//if (e.PropertyName == "Elevation")
//{
// UpdateElevation();
//}
}
}
Here is XAML.
<ContentPage.Content>
<controls:ShadowFrame Padding="10" Margin="10">
<Grid VerticalOptions="Start" HeightRequest="57" Margin="0,0,0,10" BackgroundColor="White">
<Grid ColumnSpacing="0" VerticalOptions="FillAndExpand">
<StackLayout BackgroundColor="{DynamicResource PMedium}"
x:Name="ListingLayoutB" VerticalOptions="FillAndExpand">
<Label Text="LISTING" HorizontalOptions="CenterAndExpand" TextColor="White" x:Name="ListingTxt"
FontSize="15" FontFamily="{StaticResource SBold}" VerticalOptions="CenterAndExpand"/>
</StackLayout>
<StackLayout Grid.Column="1" BackgroundColor="White" x:Name="DealsLayoutB" VerticalOptions="FillAndExpand">
<Label Text="DEALS" HorizontalOptions="CenterAndExpand" TextColor="{DynamicResource PMedium}" x:Name="DealsTxt"
FontSize="15" VerticalOptions="CenterAndExpand" FontFamily="{StaticResource SBold}"/>
</StackLayout>
</Grid>
</Grid>
</controls:ShadowFrame>
</ContentPage.Content>
And here is the result of above code. Screen shot taken from Android Emulator API level 23.
After setting BorderColor="White" the shadow is showing as expected.
Source: https://forums.xamarin.com/discussion/comment/416769#Comment_416769
I have this XAML code:
<TableView x:Name="tableView" Intent="Settings" HasUnevenRows="True">
<TableSection>
<TableSection.Title>
Card Selection
</TableSection.Title>
<ViewCell Height="50">
<Grid>
<Grid x:Name="deselectGridLink" VerticalOptions="CenterAndExpand" Padding="20, 0">
<Label TextColor="Blue" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLink" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" />
</Grid>
<Grid x:Name="deselectGridLabel" VerticalOptions="CenterAndExpand" Padding="20, 0">
<Label TextColor="Silver" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLabel" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" />
</Grid>
</Grid>
</ViewCell>
<ViewCell Height="50">
<Grid x:Name="selectGridLink" VerticalOptions="CenterAndExpand" Padding="20, 0">
<Label TextColor="Blue" Style="{DynamicResource ListItemTextStyle}" x:Name="selectLink" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Select All" />
</Grid>
</ViewCell>
</TableSection>
</TableView>
When other parts of my code call: SetPageDetails() then the label in the grid is changed to a link or the link is changed to a label. So for this when it is a label I would like to have no background flash event and no action called.
I attach a tap gesture recognizer like this. Note it's all on one line but covers two lines so it's more visible here in the SO question:
deselectGridLink.GestureRecognizers
.Add(NewTapGestureForUpdateCategories(false));
private TapGestureRecognizer NewTapGestureForUpdateCategories(bool val)
{
return new TapGestureRecognizer()
{
Command = new Command(() =>
{
App.DB.UpdateAllCategoryGroups(val);
App.DB.UpdateAllCategories(val);
GetPageData();
RemoveTableViewClickSection();
tableView.Root.Add(CreateTableSection());
})
};
}
When the user clicks the row when deselectGridLink grid is visible then:
The deselectGridLink visibility is set to false
The deselectGridLabel visibility is set to true
private void SetPageDetails()
{
Title = App.cardCountForSelectedCategories + (App.cardCountForSelectedCategories == 1 ? " Card Selected" : " Cards Selected");
if (App.cardCountForSelectedCategories == 0)
{
deselectGridLink.IsVisible = false;
deselectGridLabel.IsVisible = true;
}
else
{
deselectGridLink.IsVisible = true;
deselectGridLabel.IsVisible = false;
}
}
The effect of this is that the grid link text will change to silver and the link becomes a label.
However even though it's a gray color label when the label is clicked there is still a brief background row color change from white to a dark color when the label is clicked. I assume it's just the way a view cell works.
Is there a way to suppress this from happening?
EDIT 1 - Updated answer as per updates to question. i.e. add support for switching between highlight enabled/disabled mode.
EDIT 2 - Restructure answer and add more details.
Option-1: Enable/disable view-cell through IsEnabled
The simplest option would be to use the IsEnabled property, which in turn enables/disables the background flash behavior. The only downside to this approach is that it will also disable the taps on child controls, i.e. tap events/gesture recognizer(s) will not be triggered if parent view-cell's IsEnabled is false.
For example:
XAML
<!-- Add name attribute to view-cell -->
<ViewCell x:Name="deselectCell" ..>
<Grid>
<Grid x:Name="deselectGridLink" ..
....
</ViewCell>
Code-behind
private void SetPageDetails()
{
if (App.cardCountForSelectedCategories == 0)
{
deselectCell.IsEnabled = false; //disable background flash
...
}
else
{
deselectCell.IsEnabled = true;
...
}
}
Recommendation 1 - Use data-binding and triggers
Instead of controlling visibility for each label in code-behind, you can use triggers and data-binding as follows (view-model will have a IsDeselectEnabled property):
<ViewCell IsEnabled="{Binding IsDeselectEnabled}" Height="50">
<Label Margin="20,0,20,0" Style="{DynamicResource ListItemTextStyle}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding IsDeselectEnabled}" Value="true">
<Setter Property="TextColor" Value="Blue" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding IsDeselectEnabled}" Value="false">
<Setter Property="TextColor" Value="Silver" />
</DataTrigger>
</Label.Triggers>
</Label>
</ViewCell>
Recommendation 2 - Use triggers with view as source
<ViewCell x:Name="deselectCell" Height="50">
<Label Margin="20,0,20,0" Style="{DynamicResource ListItemTextStyle}" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding IsEnabled, Source={x:Reference deselectCell}}" Value="true">
<Setter Property="TextColor" Value="Blue" />
</DataTrigger>
<DataTrigger TargetType="Label" Binding="{Binding IsEnabled, Source={x:Reference deselectCell}}" Value="false">
<Setter Property="TextColor" Value="Silver" />
</DataTrigger>
</Label.Triggers>
</Label>
</ViewCell>
Option-2: Enable/disable highlight, but allow taps
To allow taps while toggling ViewCell's background-highlight behavior, we will need to implement platform-renderer(s).
In case of iOS, we can use SelectionStyle to toggle this behavior, while in case of android, we can use Clickable property.
Shared control:
public class CustomViewCell : ViewCell
{
public static readonly BindableProperty AllowHighlightProperty =
BindableProperty.Create(
"AllowHighlight", typeof(bool), typeof(CustomViewCell),
defaultValue: true);
public bool AllowHighlight
{
get { return (bool)GetValue(AllowHighlightProperty); }
set { SetValue(AllowHighlightProperty, value); }
}
}
iOS renderer:
[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace SampleApp.iOS
{
public class CustomViewCellRenderer : ViewCellRenderer
{
UITableViewCell _nativeCell;
//get access to the associated forms-element and subscribe to property-changed
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
_nativeCell = base.GetCell(item, reusableCell, tv);
var formsCell = item as CustomViewCell;
if (formsCell != null)
{
formsCell.PropertyChanged -= OnPropertyChanged;
formsCell.PropertyChanged += OnPropertyChanged;
}
//and, update the style
SetStyle(formsCell);
return _nativeCell;
}
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var formsCell = sender as CustomViewCell;
if (formsCell == null)
return;
//TODO: Trying to find a nicer and more robust way to dispose and unsubscribe :(
if (_nativeCell == null)
formsCell.PropertyChanged -= OnPropertyChanged;
if (e.PropertyName == CustomViewCell.AllowHighlightProperty.PropertyName)
{
SetStyle(formsCell);
}
}
private void SetStyle(CustomViewCell formsCell)
{
//added this code as sometimes on tap, the separator disappears, if style is updated before tap animation finishes
//https://stackoverflow.com/questions/25613117/how-do-you-prevent-uitableviewcellselectionstylenone-from-removing-cell-separato
Device.StartTimer(TimeSpan.FromMilliseconds(50), () => {
Device.BeginInvokeOnMainThread(() =>
{
if (formsCell.AllowHighlight)
_nativeCell.SelectionStyle = UITableViewCellSelectionStyle.Default;
else
_nativeCell.SelectionStyle = UITableViewCellSelectionStyle.None;
});
return false;
});
}
}
}
Android renderer:
[assembly: ExportRenderer(typeof(CustomViewCell), typeof(CustomViewCellRenderer))]
namespace SampleApp.Droid
{
public class CustomViewCellRenderer : ViewCellRenderer
{
Android.Views.View _nativeCell;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context)
{
_nativeCell = base.GetCellCore(item, convertView, parent, context);
SetStyle();
return _nativeCell;
}
// this one is simpler as the base class has a nice override-able method for our purpose - so we don't need to subscribe
protected override void OnCellPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnCellPropertyChanged(sender, e);
if(e.PropertyName == CustomViewCell.AllowHighlightProperty.PropertyName)
{
SetStyle();
}
}
private void SetStyle()
{
var formsCell = Cell as CustomViewCell;
if (formsCell == null)
return;
_nativeCell.Clickable = !formsCell.AllowHighlight;
}
}
}
Sample usage 1 - Through data-binding
<local:CustomViewCell AllowHighlight="{Binding IsHighlightEnabled}" ..>
<Grid>
<Grid x:Name="deselectGridLink" ..
...
</local:CustomViewCell>
Sample usage 2 - Through code-behind
XAML
<!-- Add name attribute to view-cell -->
<local:CustomViewCell x:Name="deselectCell" ..>
<Grid>
<Grid x:Name="deselectGridLink" ..
...
</local:CustomViewCell>
Code-behind
private void SetPageDetails()
{
if (App.cardCountForSelectedCategories == 0)
{
deselectCell.AllowHighlight= false; //disable background flash
...
}
else
{
deselectCell.AllowHighlight= true;
...
}
}
Option-3: Disable highlight, selection for all items
This particularly applies to ListView. The updated question now specifies that the cells are part of TableView, so this option is no longer valid in current question context.
You will need to implement platform renderers to disable highlight colors, and add ItemTapped handler to ListView to disable selection by setting SelectedItem as null always. References used:
Disable highlight item
Disable selection
Code
To get started, create a custom view-cell:
public class NoSelectViewCell : ViewCell { }
Implement iOS renderer as:
[assembly: ExportRenderer(typeof(NoSelectViewCell), typeof(NoSelectViewCellRenderer))]
namespace SampleApp.iOS
{
public class NoSelectViewCellRenderer : ViewCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var nativeCell = base.GetCell(item, reusableCell, tv);
nativeCell.SelectionStyle = UITableViewCellSelectionStyle.None;
return nativeCell;
}
}
}
Implement android renderer as:
[assembly: ExportRenderer(typeof(NoSelectViewCell), typeof(NoSelectViewCellRenderer))]
namespace SampleApp.Droid
{
public class NoSelectViewCellRenderer : ViewCellRenderer
{
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, Android.Views.ViewGroup parent, Android.Content.Context context)
{
var cell = base.GetCellCore(item, convertView, parent, context);
cell.Focusable = false;
cell.FocusableInTouchMode = false;
var listView = parent as Android.Widget.ListView;
if (listView != null)
{
listView.SetSelector(Android.Resource.Color.Transparent);
listView.CacheColorHint = Xamarin.Forms.Color.Transparent.ToAndroid();
}
return cell;
}
}
}
Sample Usage:
XAML
<ListView ItemTapped="Handle_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<local:NoSelectViewCell Height="50">
<Grid>
<Grid x:Name="deselectGridLink" VerticalOptions="CenterAndExpand" Padding="20, 0">
<Label TextColor="Blue" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLink" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" />
</Grid>
<Grid x:Name="deselectGridLabel" VerticalOptions="CenterAndExpand" Padding="20, 0">
<Label TextColor="Silver" Style="{DynamicResource ListItemTextStyle}" x:Name="deselectLabel" HorizontalOptions="StartAndExpand" VerticalOptions="Center" Text="Deselect All" />
</Grid>
</Grid>
</local:NoSelectViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code-behind
void Handle_ItemTapped(object sender, Xamarin.Forms.ItemTappedEventArgs e)
{
// don't do anything if we just de-selected the row
if (e.Item == null) return;
// do something with e.SelectedItem
((ListView)sender).SelectedItem = null; // de-select the row
}
What G.Sharada proposes is very nicely working for iOS, but on Android I still had blinks on click.
Adding this line to the styles file solved the problem.
<item name="android:colorActivatedHighlight">#android:color/transparent</item>
I have a problem with the ActivityIndicator in a Xamarin UWP project. The indicator is always running. I have to set the property IsVisible to hide the indicator. I want to do a platform specific condition on ActivityIndicator and to set the property IsVisible only when platform is Windows.
This is what I tried:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Views.LoginPage">
<StackLayout Padding="10" Spacing="10">
<Label Text="User" />
<Entry Text="{Binding Email}" Placeholder="User" />
<Label Text="Pass" />
<Entry Text="{Binding Password}" Placeholder="Pass" />
<Button Text="Autentificare" />
<ActivityIndicator IsRunning="{Binding IsBusy}">
<OnPlatform x:TypeArguments="x:Boolean">
<On Platform="Windows" Value="IsVisible">{Binding IsBusy}</On>
</OnPlatform>
</ActivityIndicator>
</StackLayout>
</ContentPage>
I tried to use the OnPlatform property, but I don't know how to do it correctly. Any idea?
I have tested your code and reproduce your issue. You could find the cause from source code.
void UpdateIsRunning()
{
Control.ElementOpacity = Element.IsRunning ? Element.Opacity : 0;
}
The IsRunning property is only a condition for setting the transparency of the
native Control rather than changing Active property for native control . But it does not work as expected. I will report this issue to related team. Currently there is a workaround. You could bind IsBusy to IsVisible and IsRunning just like the following.
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}"/>
UPDATE
You could create CustomActivityIndicator class that inherit ActivityIndicator. And then implement the custom renderer for it within native client project. For more please refer to the following code.
CustomActivityIndicator.cs
public class CustomActivityIndicator : ActivityIndicator
{
public CustomActivityIndicator()
{
}
}
CustomActivityIndicatorRenderer.cs
[assembly: ExportRenderer(typeof(CustomActivityIndicator), typeof(CustomActivityIndicatorRenderer))]
namespace XamarinActivatorTest.UWP
{
public class CustomActivityIndicatorRenderer : ActivityIndicatorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ActivityIndicator> e)
{
base.OnElementChanged(e);
if (Control != null)
{
UpdateStatus();
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(Element.IsRunning))
{
UpdateStatus();
}
}
private void UpdateStatus()
{
Control.ShowPaused = !Element.IsRunning;
Control.Opacity = Element.IsRunning ? 1 : 0;
}
}
}
You could bind IsRunning property directly. Because the function of IsRunningproperty was changed in your custom renderer.
<StackLayout Padding="10" Spacing="10">
<Button Text="Autentificare" Clicked="Button_Clicked"/>
<local:CustomActivityIndicator IsRunning="{Binding IsBusy}" >
</local:CustomActivityIndicator>
</StackLayout>
I have uploaded the code sample to git hub.
is there any chance to put badge count to the AppBarButton control on Windows 10, as you can do it on Android - e.g. How to display count of notifications in app launcher icon
If not, any idea what is a good practice to inform user about some new information (like new message)?
thanks!
http://i.stack.imgur.com/WjHNt.png
If you just want to create a control in an UWP app like your second picture, you can do it like below:
<Button Background="Transparent" Click="OnClick" HorizontalAlignment="Center">
<RelativePanel>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" Text=""/>
<Border Background="Red" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<TextBlock x:Name="count" Foreground="White" Text="{x:Bind tb.Text,Mode=OneWay}" FontSize="12" />
</Border>
</RelativePanel>
</Button>
<TextBox VerticalAlignment="Bottom" x:Name="tb" />
In this sample, I bind the Text of the TextBlock named "count" to a TextBox, so we can change this value.
But we can create it as an UserControl, so that we can use it repeatable. And we can use a DependencyProperty to expose the property we want to use. For example here:
<UserControl
x:Class="BadgeCountApp.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BadgeCountApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Button Background="Transparent" HorizontalAlignment="Center">
<RelativePanel>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" x:Name="text" Text="{x:Bind SymbText,Mode=OneWay}"/>
<Border Background="Red" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<TextBlock x:Name="count" Foreground="White" FontSize="12" Text="{x:Bind SymbCount,Mode=OneWay}" Visibility="Collapsed"/>
</Border>
</RelativePanel>
</Button>
</UserControl>
code behind:
public sealed partial class MyUserControl : UserControl
{
public MyUserControl()
{
this.InitializeComponent();
}
public static readonly DependencyProperty SymbTextProperty = DependencyProperty.Register("SymbText", typeof(string), typeof(MyUserControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty SymbCountProperty = DependencyProperty.Register("SymbCount", typeof(int), typeof(MyUserControl), new PropertyMetadata(0, new PropertyChangedCallback(ChangedCallback)));
private static void ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyUserControl muc = (MyUserControl)d;
int value = (int)e.NewValue;
if (value == 0)
{
muc.count.Visibility = Visibility.Collapsed;
}
else
{
muc.count.Visibility = Visibility.Visible;
}
}
public string SymbText
{
get { return (string)GetValue(SymbTextProperty); }
set { SetValue(SymbTextProperty, value); }
}
public int SymbCount
{
get{ return (int)GetValue(SymbCountProperty);}
set{ SetValue(SymbCountProperty, value);}
}
}
Now you can use this control directly in other place like this:
<local:MyUserControl x:Name="user" SymbText="" Tapped="OnTapped"/>
code behind:
private void OnTapped(object sender, TappedRoutedEventArgs e)
{
if (user.SymbCount == 0)
user.SymbCount = 3;
else
user.SymbCount = 0;
}
The following is a screenshot of this UserControl: