Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
just wonder to know how to set it up to Xamarin CarouselViewControl? I manage to find it in other product but not in Xamarin?
Please help.
You can implement this by attaching Behaviour to the CarouselViewControl
XAML:
xmlns:cv="clr-namespace:CarouselView.FormsPlugin.Abstractions;assembly=CarouselView.FormsPlugin.Abstractions"
xmlns:behaviour="clr-namespace:TestApp.Behaviours;assembly=TestApp"
<cv:CarouselViewControl x:Name="carousel"
ItemsSource="{Binding MySampleItems}"
ShowIndicators="true"
Orientation="Horizontal">
<cv:CarouselViewControl.Behaviors>
<behaviour:AutoscrollCarouselBehavior />
</cv:CarouselViewControl.Behaviors>
<cv:CarouselViewControl.ItemsSource>
<!--Content of Carousel goes here-->
</cv:CarouselViewControl.ItemsSource>
</cv:CarouselViewControl>
AutoscrollCarouselBehavior.cs Reference
public class AutoscrollCarouselBehavior : Behavior<CarouselView.FormsPlugin.Abstractions.CarouselViewControl>
{
/// <summary>
/// Scroll delay in milliseconds
/// </summary>
public int Delay { get; set; } = 3000;
private bool runTimer;
private CarouselViewControl attachedCarousel;
protected override void OnAttachedTo(CarouselViewControl bindable)
{
base.OnAttachedTo(bindable);
runTimer = true;
attachedCarousel = bindable;
Device.StartTimer(TimeSpan.FromMilliseconds(Delay), () =>
{
MoveCarousel();
return runTimer;
});
}
protected override void OnDetachingFrom(CarouselViewControl bindable)
{
runTimer = false;
base.OnDetachingFrom(bindable);
}
void MoveCarousel()
{
if (attachedCarousel.ItemsSource != null)
{
if (attachedCarousel.Position < attachedCarousel.ItemsSource.GetCount() - 1)
{
attachedCarousel.Position++;
}
else
{
attachedCarousel.Position = 0;
}
}
}
}
This will auto scroll the carousel page, you can set the Delay as per the requirement.
The stock Xamarin.Forms CarouselView does not support this at this time. The team is working on reimplementing the CarouselView from the ground up and "auto slide" is on the list as well.
You can find the full proposal and progress here: https://github.com/xamarin/Xamarin.Forms/issues/4996
Related
I have a carousal view in my xamarin.forms app. I am trying to implement a feature just like stories in instagram. That is when we tap any of story, it will show inside a carousal sort of view and auto slide to next story after certain seconds.
I can auto slide the carousal view after certain seconds using timer. The problem I am facing is since the content of carousal items is loaded from URL (eg: image), the view will auto slide after the predefined time without the loading the content from URL. How can I tackle this problem, ie: the carousal should only slide after the content is loaded. Any help is really appreciated.
Current auto slide implementation
Device.StartTimer(TimeSpan.FromSeconds(7), (Func<bool>)(() =>
{
Device.BeginInvokeOnMainThread(() =>
{
StatusCarousal.Position = (StatusCarousal.Position + 1) % statusList.Count;
});
return false;
}));
EDIT
My current progress.
I have created an auto sliding carousalview using Behaviors like this.
public class AutoscrollCarouselBehavior : Behavior<CarouselView.FormsPlugin.Abstractions.CarouselViewControl>
{
public int Delay { get; set; } = 7000;
private bool runTimer;
private CarouselViewControl attachedCarousel;
protected override void OnAttachedTo(CarouselViewControl bindable)
{
base.OnAttachedTo(bindable);
runTimer = true;
attachedCarousel = bindable;
Device.StartTimer(TimeSpan.FromMilliseconds(Delay), () =>
{
MoveCarousel();
return runTimer;
});
}
protected override void OnDetachingFrom(CarouselViewControl bindable)
{
runTimer = false;
base.OnDetachingFrom(bindable);
}
void MoveCarousel()
{
if (attachedCarousel.ItemsSource != null)
{
if (attachedCarousel.Position < attachedCarousel.ItemsSource.GetCount() - 1)
{
attachedCarousel.Position++;
}
else
{
attachedCarousel.Position = 0;
}
}
}
}
Xaml
<cv:CarouselViewControl x:Name="StatusCarousal"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource personDataTemplateSelector}"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<cv:CarouselViewControl.Behaviors>
<local:AutoscrollCarouselBehavior />
</cv:CarouselViewControl.Behaviors>
</cv:CarouselViewControl>
And also added additional properties for progressbar to progress.
public static class AttachedProperties
{
public static BindableProperty AnimatedProgressProperty =
BindableProperty.CreateAttached("AnimatedProgress",
typeof(double),
typeof(ProgressBar),
0.0d,
BindingMode.OneWay,
propertyChanged: (b, o, n) =>
ProgressBarProgressChanged((ProgressBar)b, (double)n));
private static void ProgressBarProgressChanged(ProgressBar progressBar, double progress)
{
ViewExtensions.CancelAnimations(progressBar);
progressBar.ProgressTo((double)progress, 800, Easing.SinOut);
}
}
Xaml
<ProgressBar HeightRequest="1.5"
x:Name="StatusProgressBar"
local:AttachedProperties.AnimatedProgressAnimationTime=""
local:AttachedProperties.AnimatedProgress=""
HorizontalOptions="FillAndExpand" VerticalOptions="Start"
ProgressColor="Snow" Margin="10,5,10,0"></ProgressBar>
The two problem still I am facing is
How to connect the carousal view auto scroll according to the ffimage loading
from api? ie; only start the auto scroll after loading the image properly ?
How to connect the carousalview to the progressbar progress preoperty? so
that both the progressbar will load into full and the carousal gets slide?
I have xamarin forms iOS app contains a webview. The webview load a html page contains some text fields.The problem I am facing is whenever we click on the text field,the keyboard shows and the entire web page will scroll to top and the text field will become invisible.When we open the same page on a browser it works fine. I have used xam.plugins.forms.keyboard overlap for my other non webview pages. How can I fix this issue? I want the textview field should be there when we focus it .
I have seen this similar problem on this question. But it didn't solved my issue. Any help is appreciated.
My XAML
<ContentPage.Content>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<WebView x:Name="Webview"
HeightRequest="1000"
WidthRequest="1000"
IsVisible="False"
Navigating="OnNavigating"
Navigated="OnNavigated"
VerticalOptions="FillAndExpand"/>
</Grid>
</ContentPage.Content>
You can remove the plugin and implement it by yourself.
For example, you can check the source code and copy it to your project as a PageRenderer.
In the page renderer, I add a bool value to check whether you need to use this renderer or not. Here I use the ClassId to check:
bool useThisRenderer;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Page p = e.NewElement as Page;
if (p.ClassId == "0")
{
useThisRenderer = false;
}
else
{
useThisRenderer = true;
}
}
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (useThisRenderer)
{
var page = Element as ContentPage;
if (page != null)
{
var contentScrollView = page.Content as ScrollView;
if (contentScrollView != null)
return;
RegisterForKeyboardNotifications();
}
}
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
if (useThisRenderer)
{
UnregisterForKeyboardNotifications();
}
}
Then in your Xamarin.forms project, if one of your content page does not need this renderer(for example the current page you have a webview), you can set the classid = "0" to avoid this:
public MainPage()
{
InitializeComponent();
this.ClassId = "0";
}
If you need this renderer, then do nothing about this.ClassId.
I upload a sample project here and feel free to ask me any question.
To provide some context, I'm writing a Xamarin.Forms application and utilizing data binding with INotifyPropertyChanged. Currently I have an inventory counter displayed on a button. The text on this button displays the bounded "Count" variable (e.g Current Inventory: 35). When I press the button, I push a screen onto the navigation stack which allows me to edit this "Count" variable. I use the class implementation like this
public class UserInventory : INotifyPropertyChanged
{
private int count = 0;
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public int Count
{
get => Preferences.Get(nameof(Count),0);
set
{
if (count == value || value <1)
return;
Preferences.Set(nameof(Count), value);
//count = value;
//Application.Current.Properties["Count"] = count;
OnPropertyChanged(nameof(Count));
//OnPropertyChanged(nameof(displayName));
}
}
public UserInventory()
{
}
void OnPropertyChanged(string count)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(count));
}
}
I add this class in Xaml according to the tutorial on the Xamarin <ContentPage.BindingContext>
<local:UserInventory />
</ContentPage.BindingContext>
So the variables are bounded correctly and I have no issues seeing updates on the current page or when I push new pages. The issue is when I swipe back on iOS the previous screen with the button "Current Inventory: 35" does not update to reflect the new changes. If I push that screen the changes are reflected.
Is there anyway to ensure the bounded data is updated when you go back (PopAsync()) ?
Try overriding page's OnAppearing() method and call OnPropertyChanged from there.
Assuming 'UserInventory' the binded VM.....
public partial class Page1:ContentPage
{
public Page1()
{
InitializeComponent();
VM = (UserInventory)BindingContext;
}
public UserInventory VM { get; }
protected override void OnAppearing()
{
VM.Notify();
base.OnAppearing();
}
}
.
public class UserInventory: INotifyPropertyChanged
{
........
public void Notify()
{
OnPropertyChanged(nameof(Count));
}
}
Could you please let me know how can I recognize long press gesture in Xamarin Forms application?
A few days before I used TapGestureRecognizer
TapGestureRecognizer imageTap = new TapGestureRecognizer();
imageTap.Tapped += (sender, args) => this.OnClickImage;
image.GestureRecognizers.Add(imageTap);
But I don't know how to make long press gesture according to this thread from xamarin forum
It should looks something like this, but it does not work.
var dumpParam = new RelayGesture((g, x) => DisplayAlert("Title", "Hello message", "Cancel"));
book.Cover.SetValue(Gestures.InterestsProperty, new GestureCollection() {
new GestureInterest
{
GestureType = GestureType.LongPress
GestureCommand = // what should I set?
GestureParameter = dumpParam
}
});
How to set my custom handler method?
You can do it cross platform way by attaching the below behavior, as long as it is Xamarin.Forms.Button or a sub-type of it.
using System;
using System.Threading;
using System.Windows.Input;
using Xamarin.Forms;
namespace App.Controls.Behaviors
{
public class LongPressBehavior : Behavior<Button>
{
private readonly object _syncObject = new object();
private const int Duration = 1000;
//timer to track long press
private Timer _timer;
//the timeout value for long press
private readonly int _duration;
//whether the button was released after press
private volatile bool _isReleased;
/// <summary>
/// Occurs when the associated button is long pressed.
/// </summary>
public event EventHandler LongPressed;
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command),
typeof(ICommand), typeof(LongPressBehavior), default(ICommand));
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(LongPressBehavior));
/// <summary>
/// Gets or sets the command parameter.
/// </summary>
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
/// <summary>
/// Gets or sets the command.
/// </summary>
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
protected override void OnAttachedTo(Button button)
{
base.OnAttachedTo(button);
this.BindingContext = button.BindingContext;
button.Pressed += Button_Pressed;
button.Released += Button_Released;
}
protected override void OnDetachingFrom(Button button)
{
base.OnDetachingFrom(button);
this.BindingContext = null;
button.Pressed -= Button_Pressed;
button.Released -= Button_Released;
}
/// <summary>
/// DeInitializes and disposes the timer.
/// </summary>
private void DeInitializeTimer()
{
lock (_syncObject)
{
if (_timer == null)
{
return;
}
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer.Dispose();
_timer = null;
Debug.WriteLine("Timer disposed...");
}
}
/// <summary>
/// Initializes the timer.
/// </summary>
private void InitializeTimer()
{
lock (_syncObject)
{
_timer = new Timer(Timer_Elapsed, null, _duration, Timeout.Infinite);
}
}
private void Button_Pressed(object sender, EventArgs e)
{
_isReleased = false;
InitializeTimer();
}
private void Button_Released(object sender, EventArgs e)
{
_isReleased = true;
DeInitializeTimer();
}
protected virtual void OnLongPressed()
{
var handler = LongPressed;
handler?.Invoke(this, EventArgs.Empty);
if (Command != null && Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
}
}
public LongPressBehavior()
{
_isReleased = true;
_duration = Duration;
}
public LongPressBehavior(int duration) : this()
{
_duration = duration;
}
private void Timer_Elapsed(object state)
{
DeInitializeTimer();
if (_isReleased)
{
return;
}
Device.BeginInvokeOnMainThread(OnLongPressed);
}
}
}
In the XAML UI:
<Button x:Name="MyButton" Text="Long Press Me!">
<Button.Behaviors>
<behaviors:LongPressBehavior LongPressed="MyButton_LongPressed"/>
</Button.Behaviors>
</Button>
XAML UI with Command Binding:
<Button x:Name="MyButton" Text="Long Press Me!">
<Button.Behaviors>
<behaviors:LongPressBehavior Command="{Binding CommandInViewModel}"/>
</Button.Behaviors>
</Button>
Make use of XLabs.Forms nuget package, which make long press and other gesture in PCL code only.
Use of XLabs.Forms package will reduce the need of custom rendering in individual platforms...
Add XAML code in .xaml file and attached event handler in .xaml.cs file..
It is working fine in Android..
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MultiImage.Page1"
xmlns:lc="clr-namespace:XLabs.Forms.Controls;assembly=XLabs.Forms"
xmlns:lb="clr-namespace:XLabs.Forms.Behaviors;assembly=XLabs.Forms">
<ContentPage.Content>
<lc:GesturesContentView ExcludeChildren="False" GestureRecognized="GesturesContentView_GestureRecognized">
<lb:Gestures.Interests>
<lb:GestureCollection>
<lb:GestureInterest GestureType="SingleTap"/>
<lb:GestureInterest GestureType="LongPress"/>
<lb:GestureInterest GestureType="DoubleTap"/>
</lb:GestureCollection>
</lb:Gestures.Interests>
<Image Source="Myimage.png" Aspect="AspectFit" HeightRequest="100"/>
</lc:GesturesContentView>
</ContentPage.Content>
C# backend code:
private void GesturesContentView_GestureRecognized(object sender, GestureResult e)
{
switch (e.GestureType)
{
case GestureType.LongPress:
//Add code here
break;
case GestureType.SingleTap:
// Add code here
break;
case GestureType.DoubleTap:
// Add code here
break;
default:
break;
}
I recently came across this problem and found a useful post on the topic https://alexdunn.org/2017/12/27/xamarin-tip-xamarin-forms-long-press-effect/
This makes use of the RoutingEffect and goes through an example of how to create both iOS and Android implementation. The simplicity of this allows you to attach it to any view in your app without recreating code.
Surfing the internet I found the solution. There are few steps which you should reproduce.
1) Inherit the control you need the gestures on (i.e. if you want to add gesture to Xamarin.Forms.Image, create you own ImageWithLongPressGesture class).
public class ImageWithLongPressGesture : Xamarin.Forms.Image
{
public EventHandler LongPressActivated;
public void HandleLongPress(object sender, EventArgs e)
{
//Handle LongPressActivated Event
}
}
2) Expose public events for the needed gestures.
3) Create a Renderer for each platform.
4) In the Renderer, handle the gestures and bubble them to your control.
[assembly: ExportRenderer(typeof(ImageWithLongPressGesture), typeof(LongPressGestureRecognizerImageRenderer))]
namespace App1.Droid.DroidRenderers
{
public class LongPressGestureRecognizerImageRenderer : ImageRenderer
{
ImageWithLongPressGesture view;
public LongPressGestureRecognizerImageRenderer()
{
this.LongClick += (sender, args) => {
Toast.MakeText(this.Context, "Long press is activated.", ToastLength.Short).Show();
};
}
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if(e.NewElement != null)
{
view = e.NewElement as ImageWithLongPressGesture;
}
}
}
}
This solution is a hybrid of answer on xamarin forms forum and Touch and Gestures presentation by Telerik.
//To Add Programatically:
StackLayout _Containter = new StackLayout();
StackLayout _StackLayout = new StackLayout();
_StackLayout.Children.Add(new Label(){Text="Execute Me"});
GesturesContentView Gv = new GesturesContentView();
_StackLayout.SetValue(XLabs.Forms.Behaviors.Gestures.InterestsProperty, new GestureCollection() {
new GestureInterest() { GestureType = GestureType.SingleTap },
new GestureInterest() { GestureType = GestureType.LongPress },
new GestureInterest() { GestureType = GestureType.DoubleTap }
});
Gv.GestureRecognized += Gv_GestureRecognized;
Gv.ExcludeChildren = false;
Gv.Content = _StackLayout;
_Containter.Children.Add(Gv);
In order to get this to work properly on iOS, you need to use XLabs.Forms.XFormsAppiOS.Init(); in your AppDelegate.cs file just before the LoadApplication(new App()); statement.
The posted code from #zafar works if you register BindingContextChanged event.
(My post is only an add, to the original post from #zafar.)
Problem was:
if using CommandParameter="{Binding .}" resulting Parameter was always null.
You need to Register BindingContextChanged event in the OnAttachedTo function.
[...]
protected override void OnAttachedTo(Button button)
{
base.OnAttachedTo(button);
this.BindingContext = button.BindingContext;
button.BindingContextChanged += handleBindingContextChanged; //this was missing
button.Pressed += Button_Pressed;
button.Released += Button_Released;
}
private void handleBindingContextChanged(object sender, EventArgs e)
{
this.BindingContext = ((Button)sender).BindingContext;
}
protected override void OnDetachingFrom(Button button)
{
base.OnDetachingFrom(button);
this.BindingContext = null;
button.Pressed -= Button_Pressed;
button.Released -= Button_Released;
button.BindingContextChanged -= handleBindingContextChanged; //also don't forget this
}
[...]
sry for the errors, this is my first post (not enough Reputation for commenting).
I'm working on porting a Windows Phone 8 application to tablet, and I've bumped into a problem with the WebView API. In Windows Phone 8 and Windows 8.1, the WebBrowser and WebView controls both have a GoBack() method. However, I need my application to be compatible for Windows 8, whose WebView API does not have such a method. Are there any alternatives/workarounds that anyone's used for Windows 8 apps?
In the end I just ended up writing a wrapper for the WebView to manage the navigation stack. Here's the relevant code, for anyone who's interested. Note that I only needed to handle backwards navigation, so I used a Stack. If forwards navigation is also required, it'd probably make sense to replace the Stack with a List and store the index of the current page instead.
public class WebViewWrapper
{
private Stack<Uri> _navigationStack;
private Uri _currentUri;
public WebView WebView { get; private set; }
public bool CanGoBack
{
get { return _navigationStack.Count > 0; }
}
public WebViewWrapper(WebView _webView)
{
_navigationStack = new Stack<Uri>();
WebView = _webView;
WebView.LoadCompleted += (object s, NavigationEventArgs e) => {
if (_currentUri != null)
{
_navigationStack.Push(_currentUri);
}
_currentUri = e.Uri;
};
}
public void GoBack()
{
if (CanGoBack)
{
_currentUri = null;
WebView.Navigate(_navigationStack.Pop());
}
}
}
An example of usage would be as follows:
// Code behind for a view called WebBrowserPage
public sealed partial class WebBrowserPage : Page
{
private WebViewWrapper _webViewWrapper;
public WebBrowserPage()
{
// webView is a WebView in the xaml with x:Name="webView"
_webViewWrapper = new WebViewWrapper(webView);
}
// Other code for navigating to a Uri specified in a ViewModel.
// Event handler for a back button press
private void BackButton_Click(object sender, RoutedEventArgs e)
{
if (_webViewWrapper.CanGoBack)
{
_webViewWrapper.GoBack();
}
else
{
// Code that executes a command in the ViewModel to leave the WebBrowserPage
}
}
}
WinRT XAML Toolkit has a WebBrowser control that does some of that, but I haven't used it in any app, so I can't vouch for its quality.