I am trying to bind the widthproperty of a column definition, but can't seem to get the binding to take. Can anyone tell me how to bind to a Xamarin Grid column definition to a property?
Binding property in custom class:
public static readonly BindableProperty PointsColumnsProperty = BindableProperty.Create(nameof(PointsBarColumns), typeof(ColumnDefinitionCollection), typeof(RewardsPanel), new ColumnDefinitionCollection());
This is my property:
public GridLength PointsFill {
get => (GridLength)GetValue(PointsFillProperty);
set => SetValue(PointsFillProperty, value);
}
This is how I am setting the binding:
_pointsBar.ColumnDefinitions[0].SetBinding(ColumnDefinition.WidthProperty, nameof(PointsFill));
I was missing the binding context on the _pointsBar.
_pointsBar = new Grid
{
BackgroundColor = BasicStyle.PrimaryColor,
Style = BasicStyle.PointsAndVisits, BindingContext = this,
ColumnDefinitions =
{
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = new GridLength(100, GridUnitType.Star) }
}
};
Related
I am trying to set margins programmatically based on the data. I have used a converter for to achieve this. It works great to set the background color but I can't find how to do it to set the margin.
This is my code:
private void SetStyles()
{
Style incomingMessageStyle = new Style(typeof(Frame))
{
Setters = {
new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(221, 221, 221) },
new Setter { Property = Margin, Value = "10,10,80,0"} //MARGIN IS NOT FOUND!
}
};
Resources.Add("IncomingMessageStyle", incomingMessageStyle);
Style outgoingMessageStyle = new Style(typeof(Frame))
{
Setters = {
new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(178, 226, 129) },
new Setter { Property = Margin, Value = "10,10,0,80"} //HOW TO SET THE MARGIN HERE?
}
};
Resources.Add("OutgoingMessageStyle", outgoingMessageStyle);
}
try this
new Setter { Property = View.MarginProperty, Value = new Thickness(...) }
After searching multiple blogs and videos I find that to implement the UITableView one can use MvxTableViewController, but what to use for NSTableView?
I do not find any tutorial, example that covers OSX binding TableView using MvvmCross. Any leads will be appreciated.
We don't have MvxTableViewController for macOS.
However, if you abstract from that, binding to a NSTableView is very similar to a UITableView on iOS.
private NSTableView _tableView;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_tableView = new NSTableView();
// add constraints or size otherwise
var source = new MvxTableViewSource(_tableView);
_tableView.Source = source;
var set = this.CreateBindingSet<MyViewController, MyViewModel>();
set.Bind(source).For(v => v.ItemsSource).To(vm => vm.Items);
set.Apply();
}
This will bind the ViewModel Items to the ItemsSource. However, you will still need to specify what to bind in the cell. The simplest way to do this is to provide a TableColumn.
var column = new MvxTableColumn();
column.Identifier = "First";
column.BindingText = "Text Name";
column.HeaderCell = new NSCell("Example");
_tableView.AddColumn(column);
This will bind the Text property of the TableColumn to Name in the items provided in Items in the ViewModel.
If you need more than this you will need to subclass MvxTableViewSource and override GetOrCreateViewFor and in there provide your own subclass of MvxTableCellView where you do more. This could look something as follows.
public class MyCustomCell : MvxTableCellView
{
public MyCustomCell(IntPtr handle) : base(handle)
{
}
public MyCustomCell(string bindingText) : base(bindingText)
{
this.Frame = new CGRect(0, 0, 100, 50);
TextField = new NSTextField(new CGRect(50, 0, 100, 50))
{
Editable = false,
Bordered = false
};
ImageView = new NSImageView(new CGRect(0, 0, 50, 50));
AddSubview(TextField);
AddSubview(ImageView);
this.Initialize(bindingText);
}
private string _imageUrl;
public string ImageUrl
{
get => _imageUrl;
set
{
_imageUrl = value;
ImageService.Instance.LoadUrl(_imageUrl).Into(ImageView);
}
}
}
And the table source:
public class MyTableSource : MvxTableViewSource
{
private string _bindingText;
public MyTableSource(NSTableView tableView, string bindingText) : base(tableView)
{
_bindingText = bindingText;
}
public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
{
if (ItemsSource == null)
return null;
var item = ItemsSource.ElementAt((int)row);
var view = new MyCustomCell(_bindingText);
if (view is IMvxDataConsumer bindable)
bindable.DataContext = item;
return view;
}
}
Then instead of using MvxTableViewSource in the first example, use your own MyTableSource instead:
var source = new MyTableViewSource(_tableView, "Text Name; ImageUrl Url");
_tableView.Source = source;
Where Name and Url are in the Item in the Items bound to the ItemsSource.
I'm setting the ItemSource of a listview and trying to create multiple Labels within the listview DataTemplate based on the children of a property of that particular item (the items are gigs, and they have a list of band members and im trying to list the band members).
I'm not sure how to get the properties of the current item that's having it's template created, can someone help?
ListView listView = new ListView {
ItemsSource = viewModel.gigs,
ItemTemplate = new DataTemplate (() => {
var grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star)});
for(int x = 0;x<=viewModel.bandMembers.Count;x++) {
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star)});
}
var venueName = new Label { Text = "Top Left" };
venueName.SetBinding (Label.TextProperty, "Venue");
grid.Children.Add(venueName, 0, 0);
for(int x = 0;x<THISITEM.bandMembers.Count;x++) {
grid.Children.Add(new Label() {Text="Test"},x,0);
}
return new ViewCell { View = grid };
});
// Build the page.
this.Content = new StackLayout {
Children = {
header,
listView
}
};
You can override OnBindingContextChnaged function in ViewCell and get the ItemData from BindingContext
I have a label style defined like:
var myLabelStyle = new Style(typeof(Label))
{
Setters =
{
new Setter { Property = Label.TextColorProperty, Value = Color.Blue },
new Setter { Property = Label.FontSizeProperty, Value = 30 }
}
};
Then I have a label defined like this:
var myLabel = new Label
{
Text = "My Label",
Style = myLabelStyle,
TextColor = Color.Red
};
Shouldn't the color of that label be Red? Well, it's blue.
I should be able to override any given property defined in a Style, according to intuition and Xamarin docs (see the single sentence after the screenshot).
What gives?
It appears to be a Xamarin Forms bug introduced somewhere between Version 2.0.0.6482 (works as expected) and Version 2.2.0.31 (broken! does not work as expected).
I do not see anything wrong with your code:, it is working in this example:
var myLabelStyle = new Style(typeof(Label))
{
Setters =
{
new Setter { Property = Label.TextColorProperty, Value = Color.Blue },
new Setter { Property = Label.FontSizeProperty, Value = 30 }
}
};
var myLabelRed = new Label
{
Text = "My Red Label",
Style = myLabelStyle,
TextColor = Color.Red
};
var myLabelBlue = new Label
{
Text = "My Blue Label",
Style = myLabelStyle,
};
var content = new ContentPage
{
Content = new StackLayout
{
Children = {
myLabelRed,
myLabelBlue
}
}
};
iOS:
Android:
I have a custom ViewCell. I was wondering if I could add a command to it, which would navigate to another page, when the ViewCell is clicked.
Below is what I have so far:
public class MainMenuItem : ViewCell
{
public MainMenuItem(string text, string icon)
{
View = new StackLayout()
{
Spacing = 10,
Padding = 10,
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
Children = {
new Image() {
Source = ImageSource.FromFile(icon),
HorizontalOptions = LayoutOptions.Start,
HeightRequest = 30,
WidthRequest = 30,
},
new Label() {
Text = text,
HorizontalOptions = LayoutOptions.Start,
FontSize = 18,
},
new Image() {
Source = ImageSource.FromFile("listitem_next.png"),
HeightRequest = 12,
HorizontalOptions = LayoutOptions.EndAndExpand
}
}
};
View = View;
}
}
Above is my view cell. Now I render these within Table sections of a TableView. And here is the code for that:
TableView tvProfile = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Form,
Root = new TableRoot {,
new TableSection ("Emergency Contacts")
{
new MainMenuItem("Contacts", "icon_phone.png")
},
new TableSection ("Check in Timers")
{
new MainMenuItem("Timers", "icon_clock.png")
},
new TableSection ("Medical Information")
{
new MainMenuItem("Medcial Info", "icon_medicalkit.png")
}
}
};
What I want is, when the user selects an Item (the ViewCell), I want to navigate the user to the respective page.
How do I do this using a command? If it's even possible. I'm new to using commands, so whatever I've gotten on the web has gone over my head.
Any help on this would be HUGELY appreciated.
Here is a quick'n'dirty implementation. Add command and commandParameter to constructor and add GestureRecognizer which calls this command.
public class MainMenuItem : ViewCell
{
public MainMenuItem(string text, string icon, ICommand command, Func<Page> commandParameterFunc)
{
View = new StackLayout()
{
...
};
View.GestureRecognizers.Add(new TapGestureRecognizer { Command = command, CommandParameter = commandParameterFunc });
}
}
Then do the following changes - create a command and add 2 parameters to every cell. Here you define the command, what happens when you click and a parameter for the command, which is a Page (but you should not create it here already and check for errors).
Update: I changed to pass a function instead of an object, so the Page is created on click. Still a bit dirty ;)
public class MyPage : ContentPage
{
private readonly ICommand _navigateCommand;
public MyPage()
{
_navigateCommand = new Command(commandParamter => Navigation.PushModalAsync((commandParamter as Func<Page>)())));
TableView tvProfile = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Form,
Root = new TableRoot
{
new TableSection ("Emergency Contacts")
{
new MainMenuItem("Contacts", "icon_phone.png", _navigateCommand, () => new ContactsPage())
},
new TableSection ("Check in Timers")
{
new MainMenuItem("Timers", "icon_clock.png", _navigateCommand, () => new TimersPage())
},
new TableSection ("Medical Information")
{
new MainMenuItem("Medcial Info", "icon_medicalkit.png", _navigateCommand, () => new MedicalInfoPage())
}
}
};
Content = tvProfile;
}
}