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;
//...
}
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 have implemented the HVScrollView custom renderer in Xamarin.Forms as below and am trying to set the background colour of the item selected on tapped/clicked but can't figure out how to do that.
I can't figure out whether I need to add something to the custom renderer to make it show the selected item or whether it should be set in my markup.
Please help
public class HVScrollGridView : Grid
{
private ICommand _innerSelectedCommand;
private readonly ScrollView _scrollView;
private readonly StackLayout _itemsStackLayout;
public event EventHandler SelectedItemChanged;
public StackOrientation ListOrientation { get; set; }
public double Spacing { get; set; }
public static readonly BindableProperty SelectedCommandProperty =
BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HVScrollGridView), null);
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(HVScrollGridView), default(IEnumerable<object>), BindingMode.TwoWay, propertyChanged: ItemsSourceChanged);
public static readonly BindableProperty SelectedItemProperty =
BindableProperty.Create("SelectedItem", typeof(object), typeof(HVScrollGridView), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public static readonly BindableProperty ItemTemplateProperty =
BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(HVScrollGridView), default(DataTemplate));
public ICommand SelectedCommand
{
get { return (ICommand)GetValue(SelectedCommandProperty); }
set { SetValue(SelectedCommandProperty, value); }
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
private static void ItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var itemsLayout = (HVScrollGridView)bindable;
itemsLayout.SetItems();
}
public HVScrollGridView()
{
_scrollView = new ScrollView();
_itemsStackLayout = new StackLayout
{
BackgroundColor = BackgroundColor,
Padding = Padding,
Spacing = Spacing,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scrollView.BackgroundColor = BackgroundColor;
_scrollView.Content = _itemsStackLayout;
Children.Add(_scrollView);
}
protected virtual void SetItems()
{
_itemsStackLayout.Children.Clear();
_itemsStackLayout.Spacing = Spacing;
_innerSelectedCommand = new Command<View>(view =>
{
SelectedItem = view.BindingContext;
SelectedItem = null; // Allowing item second time selection
});
_itemsStackLayout.Orientation = ListOrientation;
_scrollView.Orientation = ListOrientation == StackOrientation.Horizontal
? ScrollOrientation.Horizontal
: ScrollOrientation.Vertical;
if (ItemsSource == null)
{
return;
}
foreach (var item in ItemsSource)
{
_itemsStackLayout.Children.Add(GetItemView(item));
}
_itemsStackLayout.BackgroundColor = BackgroundColor;
SelectedItem = null;
}
protected virtual View GetItemView(object item)
{
var content = ItemTemplate.CreateContent();
var view = content as View;
if (view == null)
{
return null;
}
view.BindingContext = item;
var gesture = new TapGestureRecognizer
{
Command = _innerSelectedCommand,
CommandParameter = view
};
AddGesture(view, gesture);
return view;
}
private void AddGesture(View view, TapGestureRecognizer gesture)
{
view.GestureRecognizers.Add(gesture);
var layout = view as Layout<View>;
if (layout == null)
{
return;
}
foreach (var child in layout.Children)
{
AddGesture(child, gesture);
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
var itemsView = (HVScrollGridView)bindable;
if (newValue == oldValue && newValue != null)
{
return;
}
itemsView.SelectedItemChanged?.Invoke(itemsView, EventArgs.Empty);
if (itemsView.SelectedCommand?.CanExecute(newValue) ?? false)
{
itemsView.SelectedCommand?.Execute(newValue);
}
}
public static explicit operator ListView(HVScrollGridView v)
{
throw new NotImplementedException();
}
}
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();
}
}