Xamarin - binding to variable in datatemplate - xamarin

How do I bind a value from my object property to a variable so that I can pass it as an argument/parameter for my method "setFavoriteProduct(id_product, favnumber) which is triggered by my button "choiceButton". I require the property value "id_product".
When I bind it to Label "id_productLabel" then I can see it in the View just fine but I need to use the string value in my "setFavoriteProduct" function.
listView.ItemTemplate = new DataTemplate(() =>
{
Image productImage = new Image();
productImage.SetBinding(Image.SourceProperty, "imageURL");
//productImage.HeightRequest = 60;
productImage.HeightRequest = 120;
//productImage.WidthRequest = 60;
productImage.WidthRequest = 120;
productImage.Aspect = Aspect.AspectFit;
Label nameLabel = new Label();
nameLabel.SetBinding(Label.TextProperty, "name");
Label id_productLabel = new Label();
id_productLabel.SetBinding(Label.TextProperty, "id_product");
id_productLabel.IsVisible = true;
Button choiceButton = new Button();
choiceButton.Text = "Vali";
choiceButton.Clicked += (sender, args) => setFavoriteProduct(
id_product,
favnumber
);
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(0, 5),
Orientation = StackOrientation.Horizontal,
Children = { productImage, id_productLabel , nameLabel, choiceButton }
}
};

the simplest way to do this is to get the BindingContext from the sender (button) and then get the property from that
choiceButton.Clicked += (sender, args) => {
var context = (MyClass)((Button)sender).BindingContext;
var id = context.id_product;
setFavoriteProduct(id,favnumber);
};
alternately, you could use the Button's Command and CommandParameter properties instead of the Clicked event

Related

Why does adding datatemplate stop the display of itemsource?

This code results in a display of the same line of the table name for every one of the 230 records in the table but not the fields:
ListView lv = new ListView();
lv.ItemsSource = await App.Database.GetItemsAsync();
StackLayout sl = new StackLayout();
Label ln = new Label();
ln.SetBinding(Label.TextProperty, nameof(ContactsModel.LastName));
Label fn = new Label();
fn.SetBinding(Label.TextProperty, nameof(ContactsModel.FirstName));
sl.Children.Add(ln);
sl.Children.Add(fn);
sl.Children.Add(lv);
Content = sl;
But adding the datatemplate results in a blank screen
ListView lv = new ListView();
lv.ItemsSource = await App.Database.GetItemsAsync();
var template = new DataTemplate(typeof(ViewCell));
lv.ItemTemplate = template;
StackLayout sl = new StackLayout();
Label ln = new Label();
ln.SetBinding(Label.TextProperty, nameof(ContactsModel.LastName));
Label fn = new Label();
fn.SetBinding(Label.TextProperty, nameof(ContactsModel.FirstName));
sl.Children.Add(ln);
sl.Children.Add(fn);
sl.Children.Add(lv);
Content = sl;
first, this would be easier to do in XAML. But if you need to do it in code
var template = new DataTemplate(() =>
{
Label ln = new Label();
ln.SetBinding(Label.TextProperty, nameof(ContactsModel.LastName));
Label fn = new Label();
fn.SetBinding(Label.TextProperty, nameof(ContactsModel.FirstName));
var stack = new StackLayout();
stack.Children.Add(ln);
stack.Children.Add(fn);
return new ViewCell { View = stack };
});
lv.ItemTemplate = template;

how to add button n times on xamarin

First of all i have seen few topics about that but didnt helped i typed thoose in xamarin.
i add a button in that way
Button desk = new Button
{
Text = desknumber.ToString(),
Font = Font.SystemFontOfSize(NamedSize.Large),
BorderWidth = 1,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
so i have to run this command in loop or in a method like that
public void masaekle(int masasayisi)
{
Button desknumber = new Button
{
Text = masasayisi.ToString(),
Font = Font.SystemFontOfSize(NamedSize.Large),
BorderWidth = 1,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.CenterAndExpand
};
this.Content = new StackLayout
{
Children =
{
desknumber,
}
};
it doesnt work in any variable type so i stuck here i cant give a variable name to the button
every time you assign Content it overwrites what is already there
var sl = new StackLayout();
// some loop conditions
for(;;)
{
var button = new Button { ... };
sl.Children.Add(button);
}
this.Content = sl;

xamarin Forms - Is it possible to get Grid row selection event?

How do i get row id of grid row selection? I want to add row unique id and i want it on tapped or on clicked. please suggest me if anyone have any idea.
I want to do some thing like this, if i click on the row and i get id. with this id i will fetch another records and send user on another page. for this i need unique id of the row.
i have grid like bellow:
Below is the code i use:
public BusList(Common busdata)
{
InitializeComponent();
this.BindingContext = this;
List<BusDetail> Bus = new List<BusDetail>
{
...
new BusDetail("Nita Travel","Mumbai", "Navsari",new DateTime(2017, 3, 9), "10:15 AM", "09:15 AM")
};
Label header = new Label
{
Text = "GridView Demo",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
HorizontalOptions = LayoutOptions.Center
};
var controlGrid = new Grid
{
RowSpacing = 2,
ColumnSpacing = 2,
Margin = new Thickness(5, Device.OnPlatform(5, 0, 0), 5, 5)
};
controlGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(30) });
for (int i = 0; i < Bus.Count(); i++)
{
controlGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(30) });
}
controlGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
controlGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
controlGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
controlGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
Bus = Bus.Where(x => x.FromDest.ToLower().Contains(busdata.FromDest.ToLower()) && x.FromDate == busdata.FromDate).ToList();
controlGrid.Children.Add(new Label { Text = "ID", Font = Font.SystemFontOfSize(NamedSize.Large).WithAttributes(FontAttributes.Bold), BackgroundColor = Color.Gray }, 0, 0);
controlGrid.Children.Add(new Label { Text = "Travel Name", Font = Font.SystemFontOfSize(NamedSize.Large).WithAttributes(FontAttributes.Bold), BackgroundColor = Color.Gray }, 1, 0);
controlGrid.Children.Add(new Label { Text = "Arr Time", Font = Font.SystemFontOfSize(NamedSize.Large).WithAttributes(FontAttributes.Bold), BackgroundColor = Color.Gray }, 2, 0);
controlGrid.Children.Add(new Label { Text = "Dep Time", Font = Font.SystemFontOfSize(NamedSize.Large).WithAttributes(FontAttributes.Bold), BackgroundColor = Color.Gray }, 3, 0);
for (int i = 0; i < Bus.Count(); i++)
{
var clickableRow = new ContentView();
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, "RowTappedCommand");
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandParameterProperty, i.ToString());
clickableRow.GestureRecognizers.Add(tapGestureRecognizer);
clickableRow.BindingContext = i.ToString();
controlGrid.Children.Add(clickableRow, 0, i);
Grid.SetColumnSpan(clickableRow, 3);
controlGrid.Children.Add(new Label { Text = Bus[i].TravelName, BindingContext = Bus[i].TravelName, BackgroundColor = Color.LightGray, VerticalTextAlignment = TextAlignment.Center }, 1, i + 1);
controlGrid.Children.Add(new Label { Text = Bus[i].ArrivalTime, BindingContext = Bus[i].ArrivalTime, BackgroundColor = Color.LightGray, VerticalTextAlignment = TextAlignment.Center }, 2, i + 1);
controlGrid.Children.Add(new Label { Text = Bus[i].DepartureTime, BindingContext= Bus[i].DepartureTime, BackgroundColor = Color.LightGray, VerticalTextAlignment = TextAlignment.Center }, 3, i + 1);
}
this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);
this.Content = new StackLayout
{
Children =
{
header,
controlGrid
}
};
}
public void RowTappedCommand(string index)
{
var tappedRow = int.Parse(index);
}
You could add a ContentView to each row on the first column and span it across all columns by using the ColumnSpan property. Then you'd handle the taps with a TouchGestureListener. When creating the Command, you'd also include a CommandParameter which contains the index of the row in question.
Outside the constructor, define this:
public ICommand RowTappedCommand { get; private set; }
Then add the following code somewhere after InitializeComponent:
RowTappedCommand = new Command<string>(RowTapped);
Then create the clickable ContentView controls for each row:
var clickableRow = new ContentView {
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
}
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, "RowTappedCommand");
var binding = new Binding();
binding.Source = i.ToString();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandParameterProperty, binding); // This is the index of the row
clickableRow.GestureRecognizers.Add(tapGestureRecognizer);
controlGrid.Children.Add(clickableRow, 0, 0);
Grid.SetColumnSpan(clickableRow,3);
You also need to define the method that matches the name defined in the CommandProperty. If you have a view model defined for the view you need to do it there. Otherwise, you'll need to add the method to your view's code behind file (xaml.cs).
void RowTapped(string index)
{
var tappedRow = int.Parse(index);
// Do something with the value
}
Remember to set the BindingContext correctly so that your command gets called. Here's more information about Commands in Xamarin.Forms:
Update: There were a few mistakes that needed to be fixed.
Command wasn't defined correctly.
The binding for the command property needs to be pointing to a static value
Simplifying Events with Commanding

popup message box in xamarin.form

What I am trying to do is similar to DisplayAlert, popup a display page that contains image, content and a small close button at top right. The display page shouldn't cover the whole phone but just around 80% of the phone UI, background remain as parent page.
I am trying to play around with PushModalAsync and PopModalAsync, however with no luck. The output is not what I expected.
Basically, I have a listview, whenever item is selected from screen it will call for popUpMethod:
list.ItemSelected += MyMethod;
inside MyMethod i will call popUpPage
async void MyMethod(object sender, SelectedItemChangedEventArgs e){
Content = await PopUpPage();
}
and this is my PopUpPage method
private async Task<StackLayout> PopUpPage()
{
StackLayout objPopUp = new StackLayout() { HeightRequest = 100, WidthRequest= 100, VerticalOptions = LayoutOptions.CenterAndExpand};
Label lblMessage = new Label();
lblMessage.Text = "Welcome";
objPopUp.Children.Add(lblMessage);
return objPopUp;
}
I am trying to set the height and width inside my popup page. However, it is still covering the whole screen which is not what I want. let me know if any top up information is needed, thank you.
P/S : i designed it in xamarin.Form(portable)
You can create a custom pop-up to accomplish this in Xamarin.Forms
Here is a custom ContentView that I created. It uses a BoxView to give the appearance of fading the background, and uses a Frame to add a shadow to the pop-up.
I also use animations to make the custom pop-up appear as if it is springing off of the screen!
Sample App
The code for this sample app is available on Github:
https://github.com/brminnick/InvestmentDataSampleApp
Code Snippet
public class WelcomeView : ContentView
{
readonly BoxView _backgroundOverlayBoxView;
readonly Frame _overlayFrame;
readonly StackLayout _textAndButtonStack;
readonly RelativeLayout _relativeLayout;
public WelcomeView()
{
const string titleText = "Welcome";
const string bodyText = "Enjoy InvestmentDataSampleApp";
const string okButtonText = "Ok, thanks!";
var whiteWith75Opacity = new Color(255, 255, 255, 0.75);
_backgroundOverlayBoxView = new BoxView
{
BackgroundColor = whiteWith75Opacity
};
_backgroundOverlayBoxView.Opacity = 0;
_overlayFrame = new Frame
{
HasShadow = true,
BackgroundColor = Color.White
};
_overlayFrame.Scale = 0;
var titleLabel = new Label
{
FontAttributes = FontAttributes.Bold,
Text = titleText,
HorizontalTextAlignment = TextAlignment.Center
};
var bodyLabel = new Label
{
Text = bodyText,
HorizontalTextAlignment = TextAlignment.Center
};
var blackWith75PercentOpacity = new Color(0, 0, 0, 0.75);
var okButton = new Button
{
BackgroundColor = blackWith75PercentOpacity,
TextColor = Color.White,
BorderWidth = 1,
BorderColor = blackWith75PercentOpacity,
FontAttributes = FontAttributes.Bold,
Margin = new Thickness(5),
Text = okButtonText
};
okButton.Clicked += (sender, e) =>
{
Device.BeginInvokeOnMainThread(async () =>
{
await this.FadeTo(0);
this.IsVisible = false;
this.InputTransparent = true;
});
}
_textAndButtonStack = new StackLayout
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
Spacing = 20,
Children = {
titleLabel,
bodyLabel,
okButton
}
};
_textAndButtonStack.Scale = 0;
_relativeLayout = new RelativeLayout();
Func<RelativeLayout, double> gettextAndButtonStackHeight = (p) => _textAndButtonStack.Measure(_relativeLayout.Width, _relativeLayout.Height).Request.Height;
Func<RelativeLayout, double> gettextAndButtonStackWidth = (p) => _textAndButtonStack.Measure(_relativeLayout.Width, _relativeLayout.Height).Request.Width;
_relativeLayout.Children.Add(_backgroundOverlayBoxView,
Constraint.Constant(-10),
Constraint.Constant(0),
Constraint.RelativeToParent(parent => parent.Width + 20),
Constraint.RelativeToParent(parent => parent.Height)
);
_relativeLayout.Children.Add(_overlayFrame,
Constraint.RelativeToParent(parent => parent.Width / 2 - gettextAndButtonStackWidth(parent) / 2 - 20),
Constraint.RelativeToParent(parent => parent.Height / 2 - gettextAndButtonStackHeight(parent) / 2 - 10),
Constraint.RelativeToParent(parent => gettextAndButtonStackWidth(parent) + 30),
Constraint.RelativeToParent(parent => gettextAndButtonStackHeight(parent) + 30)
);
_relativeLayout.Children.Add(_textAndButtonStack,
Constraint.RelativeToView(_overlayFrame, (parent, view) => view.X + 15),
Constraint.RelativeToView(_overlayFrame, (parent, view) => view.Y + 15)
);
if (Device.OS == TargetPlatform.Android)
{
_overlayFrame.IsVisible = false;
_textAndButtonStack.BackgroundColor = whiteWith90Opacity;
}
Content = _relativeLayout;
}
public void DisplayView()
{
Device.BeginInvokeOnMainThread(async () =>
{
var animationList = new List<Task>
{
_backgroundOverlayBoxView.FadeTo(1,AnimationConstants.WelcomeViewAnimationTime),
_textAndButtonStack.ScaleTo(AnimationConstants.WelcomeViewMaxSize, AnimationConstants.WelcomeViewAnimationTime),
_overlayFrame.ScaleTo(AnimationConstants.WelcomeViewMaxSize,AnimationConstants.WelcomeViewAnimationTime)
};
await Task.WhenAll(animationList);
animationList = new List<Task>
{
_textAndButtonStack.ScaleTo(AnimationConstants.WelcomeViewNormalSize, AnimationConstants.WelcomeViewAnimationTime),
_overlayFrame.ScaleTo(AnimationConstants.WelcomeViewNormalSize, AnimationConstants.WelcomeViewAnimationTime)
};
await Task.WhenAll(animationList);
});
}
}
PushModalAsync will push page over your current page. Instead use same page add one frame in it. configure frame with whatever controls you want.
1. set frame Visibility to false and on ItemSelected make frame visible. OR
2. add frame dynamically on ItemSelected (haven't tried 2nd approach.).
Change your code like as following.
private async Task<StackLayout> PopUpPage () {
StackLayout objPopUp = new StackLayout () {HeightRequest = 0, WidthRequest = 0, VerticalOptions = LayoutOptions.Center, Padding = 10 };
Label lblMessage = new Label ();
lblMessage.Text = "Welcome";
objPopUp.Children.Add (lblMessage);
return objPopUp;
}
You may use the XLabs-PopUp-Control.
With that control, you can show a PopUp from you page where you can define the size without problems. I use it on various pages.
Link how to use it
Link how to install and setup XLabs

Problems with deleting items from a listbox

The behaviour Im trying to achieve is to press and hold a listbox item and I should be able to delete the item.
I have created the listbox through code. Everylistitem has a stackpanel which holds two textblocks, ie a date and a string.
How can i get press and hold event for a selectedlistitem?? I have not used binding anywhere.
C#:
for (int i = 0; i < iHistCount; i++)
{
TextBlock dateText = new TextBlock();
TextBlock durationText = new TextBlock();
TextBlock spacer = new TextBlock();
TextBlock spacer2 = new TextBlock();
dateText.FontFamily = (FontFamily)App.Current.Resources["CicleFina"];
durationText.FontFamily = (FontFamily)App.Current.Resources["CicleFina"];
dateText.FontSize = 25;
durationText.FontSize = 25;
dateText.TextAlignment = TextAlignment.Right;
durationText.TextAlignment = TextAlignment.Left;
dateText.VerticalAlignment = System.Windows.VerticalAlignment.Center;
durationText.VerticalAlignment = System.Windows.VerticalAlignment.Center;
spacer.Width = 30;
dateText.Width = 130;
spacer2.Width = 50;
durationText.Width = 170;
DateTime dtHist = pCycMan.GetHistoryDate(i);
strDisplay = dtHist.ToString("dd-MMM-yyyy");
dateText.Text = strDisplay;
if( condition)
{
// logic
durationText.Text = strDisplay;
}
StackPanel st = new StackPanel();
st.Height = 50;
st.Orientation = System.Windows.Controls.Orientation.Horizontal;
st.Children.Add(spacer);
st.Children.Add(dateText);
st.Children.Add(spacer2);
st.Children.Add(durationText);
listboxHistory.Items.Add(st);
}
XAML
<ListBox x:Name="listboxHistory" Height="280" Canvas.Left="60" Canvas.Top="232" Width="360" Foreground="Gray">
Assuming you're using the Silverlight toolkit for a context menu, this link is a good example, and has how to create the menu in code-behind.
http://windowsphonegeek.com/articles/WP7-ContextMenu-in-depth--Part1-key-concepts-and-API
For example here:
StackPanel st = new StackPanel();
st.Height = 50;
st.Orientation = System.Windows.Controls.Orientation.Horizontal;
st.Children.Add(spacer);
st.Children.Add(dateText);
st.Children.Add(spacer2);
st.Children.Add(durationText);
listboxHistory.Items.Add(st);
ContextMenu cm = new ContextMenu();
MenuItem delete = new MenuItem()
{
Header = "Delete",
Tag= "Delete" //you could also put the item itself here, would be a good reference
};
delete.Clicked += //your event handler
MenuItem edit = new MenuItem()
{
Header = "Edit",
Tag = "Edit", //you could also put the item itself here, would be a good reference
};
edit.Clicked += //your event handler
//add the items to the context menu.
cm.Items.Add(delete);
cm.Items.Add(edit);
ContextMenuService.SetContextMenu(st, cm);

Resources