I have ScrollView inside of a DataTemplate of a ListView. I have a need to horizontally auto scroll the scrollview for each item (to a different point determined by a value inside of my ViewModel which the ListItemViews are bound to).
To my knowledge there's no way to bind the scroll position. How can I call the ScrollView.ScrollToAsync method on the ScrollView inside the DataTemplate?
Thanks!
You can try to create a bindableProperty of ScrollView and bind your scroll value to this property, call the ScrollToAsync method in propertyChanged event:
public class CustomScrollView : ScrollView
{
public static readonly BindableProperty offSetProperty = BindableProperty.Create(
propertyName: nameof(offSet),
returnType: typeof(int),
declaringType: typeof(CustomScrollView),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: ScrollOffsetChanged
);
static void ScrollOffsetChanged(BindableObject bindable, object oldValue, object newValue)
{
var view = (CustomScrollView)bindable;//here you should check if the bindable is CustomScrollView, I don't see your xaml
view.offSet = (int)newValue;
view.ScrollToAsync(view.offSet, 0, true);
}
public int offSet
{
get { return (int)GetValue(offSetProperty); }
set { SetValue(offSetProperty, value); }
}
}
Related
It may sound like a dumb question but why are bindable properties static?
public static readonly BindableProperty MapSpanProperty = BindableProperty.Create
(
propertyName: "MapSpan",
returnType: typeof(MapSpan),
declaringType: typeof(BindableMap),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: MapSpanPropertyChanged
);
public MapSpan MapSpan
{
get
{
return (MapSpan)GetValue(MapSpanProperty);
}
set
{
SetValue(MapSpanProperty, value);
}
}
I have this code and it works just fine if I make the bindable property static, otherwise, it doesn't work. If I make this bindable property static it means, let's say if I have 2 maps opened at the same time, that this value will be the same on both if I set it on one of them?
Each bindable property has a corresponding public static readonly field of type BindableProperty that is exposed on the same class and that is the identifier of the bindable property.
You could check the source code of the control which provide the binable property.
I use the contentview for example. The code is from the link below. Xamarin forms update viewmodel field from a bindable property
public partial class MyCustomControl : ContentView
{
private string _text;
public string Text
{
get { return _text; }
set
{
_text = value;
OnPropertyChanged();
}
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(MyCustomControl),
string.Empty,
propertyChanged: (bindable, oldValue, newValue) =>
{
var control = bindable as MyCustomControl;
//var changingFrom = oldValue as string;
//var changingTo = newValue as string;
control.Title.Text = newValue.ToString();
});
public MyCustomControl()
{
InitializeComponent();
}
The ContentView provide the public static readonly BindableProperty.
//
// Summary:
// An element that contains a single child element.
//
// Remarks:
// The following example shows how to construct a new ContentView with a Label inside.
[ContentProperty("Content")]
public class ContentView : TemplatedView
{
//
// Summary:
// Backing store for the Xamarin.Forms.ContentView.Content property..
//
// Remarks:
// To be added.
public static readonly BindableProperty ContentProperty;
public ContentView();
//
// Summary:
// Gets or sets the content of the ContentView.
public View Content { get; set; }
//
// Summary:
// Method that is called when the binding context changes.
//
// Remarks:
// To be added.
protected override void OnBindingContextChanged();
}
You could check the MS docs about more for the static in binable property. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/bindable-properties
I created a bindableproperty in a customview but it can not get value.
here is the code:
public string BackgroundImage
{
get
{
var image = (image)GetValue(BackgroundImageProperty);
return image;
}
set => SetValue(BackgroundImageProperty, value);
}
the image is null.
public static readonly BindableProperty BackgroundImageProperty = BindableProperty.Create(nameof(BackgroundImage), typeof(string), typeof(MyView), null);
the xaml code:
<local:MyView BackgroundImage="back.png" />
I do want give a string value and give it to a Image.
I have give the BackgroundImage a string value in the xaml.
Solution1:
You can get the value from the event propertyChanged
public static readonly BindableProperty TextProperty = BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(MyView),
null,
propertyChanged: (bindable, oldValue, newValue) =>
{
var value = newValue;
// do some thing you want .
}
);
Solution 2:
You can set the BindingContext in CustomView .
public MyView
{
//...
BindingContext = this;
//...
}
My view...
public partial class TableRow : ViewCell
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create("Text", typeof(string), typeof(TableRow), null);
public string Text
{
get => (string)GetValue(TextProperty);
set
{
SetValue(TextProperty, value);
lblValue.Text = value;
}
}
Used like this...
<Custom:TableRow NameText="Name" Text="{Binding Name}" />
But when I set the binding context...
BindingContext = candidate;
... you've guessed it! Nothing happens!
What's the missing step?
It's the page's BindingContext that candidate is set to.
I would like set in may custom class font size. Do you now how I can do this?
CustomButton class
public static readonly BindableProperty PaddingProperty =
BindableProperty.Create(
nameof(Padding),
typeof(Thickness),
typeof(CustomButton),
new Thickness(0, 0, 0, 0));
public static readonly BindableProperty TypeProperty =
BindableProperty.Create(
nameof(Type),
typeof(TypeEnum),
typeof(CustomButton),
TypeEnum.Blue
);
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
If your "custom button" inherits from Xamarin.Forms.Button you can just set its "FontSize" property.
public class CustomButton : Xamarin.Forms.Button //Inheriting from Xamarin.Forms.Button!
{
public static readonly BindableProperty PaddingProperty =
BindableProperty.Create(
nameof(Padding),
typeof(Thickness),
typeof(CustomButton),
new Thickness(0, 0, 0, 0));
public static readonly BindableProperty TypeProperty =
BindableProperty.Create(
nameof(Type),
typeof(TypeEnum),
typeof(CustomButton),
TypeEnum.Blue
);
public Thickness Padding
{
get { return (Thickness)GetValue(PaddingProperty); }
set { SetValue(PaddingProperty, value); }
}
public CustomButton()
{
FontSize = 123; //FontSize property on Xamarin.Forms.Button
}
}
Below is the BindableProperty definition on a custom control:
public static BindableProperty ItemsSourceProperty =
BindableProperty.Create<NodeListView, IEnumerable<Node>> (ctrl =>
ctrl.ItemsSource,defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanging: (bindable, oldValue, newValue) => {
var ctrl = (NodeListView)bindable;
ctrl.ItemsSource = newValue;
});
public IEnumerable<Node> ItemsSource {
get {
var itemsSource = (IEnumerable<Node>)GetValue (ItemsSourceProperty);
return itemsSource;
}
set {
SetValue (ItemsSourceProperty, value);
BindNodeIcons ();
}
}
When I set the BindingContext on the control I can see the newValue in propertyChanging is set to a correct object. Also in the setter of ItemsSource property the value variable takes the correct value. In the BindNodeIcons() method, I access ItemsSource property and it returns null. I can't see anything wrong in the code but still.
Try the following:
public class NodeListView : BindableObject
{
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable<Node>), typeof(NodeListView), propertyChanged: OnItemSourceChanged);
public IEnumerable<Node> ItemsSource
{
get { return (IEnumerable<Node>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void OnItemSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var nodeListView = bindable as NodeListView;
nodeListView.BindNodeIcons();
}
}