How to access components created in Xamarin.Forms C# code behind? - c#

So, I'm doing an app in Xamarin.Forms that creates some components and layouts when a button is clicked.
My problem is that I need to access these components afterwards so I can change the text in some labels, get values from editors and remove them later if necessary...
This is the piece of code that creates the components:
private void newItem()
{
StackLayout add = new StackLayout { };
add.StyleId = "add_" + posicio;
elements.Children.Add(add);
StackLayout grupInical = new StackLayout
{
Orientation = StackOrientation.Horizontal
};
add.Children.Add(grupInical);
Label number = new Label
{
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.StartAndExpand,
Text = "Element" + posicio.ToString(),
FontAttributes = FontAttributes.Bold,
Margin = new Thickness(5, 0, 0, 0)
};
Button tancar = new Button
{
Padding = new Thickness(5),
Text = "✕",
HorizontalOptions = LayoutOptions.End,
BackgroundColor = Color.Transparent,
WidthRequest = 30,
HeightRequest = 30
};
number.StyleId = "number_" + posicio;
tancar.StyleId = "tancar_" + posicio;
tancar.Clicked += Eliminar_clicked;
grupInical.Children.Add(number_);
grupInical.Children.Add(tancar);
StackLayout values = new StackLayout
{
Orientation = StackOrientation.Horizontal
};
values.StyleId = "values" + posicio;
add.Children.Add(values);
Button elegir = new Button
{
Text = "Element"
};
Editor percentage = new Editor { MaxLength = 2, WidthRequest = 30 };
Label desc = new Label
{
VerticalOptions = LayoutOptions.Center,
FontSize = 20,
FontAttributes = FontAttributes.Bold,
Text = "%"
};
Picker picker = new Picker
{
IsVisible = false
};
elegir.Clicked += Elegir_Clicked;
elegir.StyleId = "elegir_"+posicio;
percentatge.StyleId = "percentatge_" + posicio;
desc.StyleId = "desc_" + posicio;
picker.StyleId = "picker_" + posicio;
values.Children.Add(elegir);
values.Children.Add(percentatge);
values.Children.Add(desc);
values.Children.Add(picker);
posicio += 1;
scroll.ScrollToAsync(0, elements.Height, true);
}
As you can see, I'm trying to access the components by assigning them a styleid value but I can't access the component.
Have you got any suggestions on how to identify the items so I can reference them later on?

Declare these components at the class level and then you can access them in the other place in your project.
public partial class MainPage : ContentPage
{
Label numberLabel;
StackLayout myAddStackLayout;
public MainPage()
{
InitializeComponent();
newItem()
numberLabel.Text = "updateValue";
myAddStackLayout.Children.Add(...);
}
public void test() {
numberLabel.Text = "updateValue";
myAddStackLayout.Children.Add(...);
}
private void newItem()
{
StackLayout add = new StackLayout { };
Label number = new Label ();
}
}

Related

Microsoft Android Emulator Shows Blank Form When Debugging

I am trying to run a Xamarin form called 'FormsApp' on my andriod emulator in visual studio. The Emulator boots up fine and renders. However, after clicking "start debugging" the form deploys to the emulator but only shows a blank white from.
https://i.imgur.com/AbkqDyJ.png
https://i.imgur.com/VttMKfh.png
I have tried playing around with my OpenGL ES Renderer settings and OpenGL ES API level settings as well. Switching to swiftshader/ANGLE D3D9/ and Compatibility (OpenGL ES 1.1/2.0) did not work. It's Still a blank white Screen when debugging.
namespace FormsApp
{
class ContentPageExample : ContentPage
{
public ContentPageExample()
{
Label labelLarge = new Label
{
Text = "Label",
FontSize = 40,
HorizontalOptions = LayoutOptions.Center
};
Label labelSmall = new Label
{
Text = "This control is great for\n" +
"displaying one or more\n" +
"lines of text.",
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
Button button = new Button
{
Text = "Make It So",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Fill
};
button.Clicked += (sender, args) =>
{
button.Text = "It is so!";
};
Entry entry = new Entry
{
Placeholder = "Username",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text
};
BoxView boxView = new BoxView
{
Color = Color.Silver,
WidthRequest = 150,
HeightRequest = 150,
HorizontalOptions = LayoutOptions.StartAndExpand,
VerticalOptions = LayoutOptions.Fill
};
Image image = new Image
{
Source = "monkey.png",
Aspect = Aspect.AspectFit,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Fill
};
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += async (sender, e) =>
{
image.Opacity = .5;
await Task.Delay(200);
image.Opacity = 1;
};
image.GestureRecognizers.Add(tapGestureRecognizer);
StackLayout stackLayout = new StackLayout
{
Children =
{
labelLarge,
labelSmall,
button,
entry,
boxView,
image
},
HeightRequest = 1500
};
ScrollView scrollView = new ScrollView
{
//BackgroundColor = Color.White,
VerticalOptions = LayoutOptions.FillAndExpand,
Content = stackLayout
};
//this.BackgroundColor = Color.Black; //White
// Accomodate iPhone status bar.
this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);
this.Content = scrollView;
}
}
}
No error messages..
Did you set the ContentPageExample as MainPage? I just test the ContentPageExample and it works well.
For example in class App:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new ContentPageExample();
}
}

How do I send data back to the parent page in xamarin forms?

There is a label in the page Account which when tapped on will create a new ContentPage with a list of premise addresses. Tapping on any of the addresses should pop the ContentPage and send back a value to the Account page to set certain fields within the Account page. I tried to use Messaging center but it doesn't seem to be able to get the value. What am I missing?
This is the code that creates the ContentPage with the premise addresses:
private void ddlPremisesAddNavigation()
{
PremiseListPage = CreatePAContentPage();
var tgrddlPremiseAddress = new TapGestureRecognizer();
NavigationPage.SetHasNavigationBar(PremiseListPage, false);
tgrddlPremiseAddress.Tapped += (s, e) =>
{
Navigation.PushAsync(PremiseListPage);
};
// ddlPremiseAddresses.GestureRecognizers.Add(tgrddlPremiseAddress);
lblpremiseAddress.GestureRecognizers.Add(tgrddlPremiseAddress);
}
private ContentPage CreatePAContentPage()
{
#region Containers
ContentPage content = new ContentPage();
StackLayout pageContent = new StackLayout();
ScrollView addressesView = new ScrollView()
{
// BackgroundColor = Color.White,
Padding = new Thickness(20, 10, 20, 10)
};
StackLayout addressContainer = new StackLayout();
#endregion
#region Header
RowDefinitionCollection RowDefinitions = new RowDefinitionCollection();
ColumnDefinitionCollection ColumnDefinitions = new ColumnDefinitionCollection();
RowDefinitions.Add(new RowDefinition { Height = new GridLength(50, GridUnitType.Absolute) });
Grid header = new Grid()
{
RowDefinitions = RowDefinitions,
};
BoxView bg = new BoxView() { HeightRequest = 50, WidthRequest = 250, BackgroundColor = Color.White };
header.Children.Add(bg, 0, 0);
Grid.SetColumnSpan(bg, 5);
Label title = new Label()
{
Text = "Premise Address",
FontSize = 15,
FontAttributes = FontAttributes.Bold,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
header.Children.Add(title, 1, 0);
Grid.SetColumnSpan(title, 3);
Button back = new Button() { Image = "backArrow", BackgroundColor = Color.White };//
header.Children.Add(back, 0, 0);
Grid.SetColumnSpan(back, 1);
back.Clicked += back_Clicked;
#endregion
#region Address Frames
List<Frame> addrFrames = new List<Frame>();
if (premiseAddresses.Count <= 0)
{
foreach (PremisesModel premise in Premises)
{
premiseAddresses.Add(premise.PremiseId, premise.PremiseAddress);
}
}
foreach (KeyValuePair<int,string> item in premiseAddresses)
{
addrFrames.Add(CreatePAFrame(item));
}
#endregion
#region Add Content to Containers
foreach (Frame item in addrFrames)
{
addressContainer.Children.Add(item);
}
// < Button x: Name = "btnReqAmendment" Text = "Request amendment" Style = "{StaticResource buttonStyle}" Clicked = "btnReqAmendment_Clicked" />
Button addNew = new Button()
{
Text = "ADD NEW PREMISE ADDRESS",
Style = Application.Current.Resources["buttonStyle"] as Style,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Margin = new Thickness(0, 20, 2, 15)
//FontSize = 12,
//WidthRequest = 220,
//HeightRequest = 40
};
addNew.Clicked += btnAddNewPremise_Clicked;
addressContainer.Children.Add(addNew);
addressesView.Content = addressContainer;
pageContent.Children.Add(header);
pageContent.Children.Add(addressesView);
content.Content = pageContent;
#endregion
return content;
}
private Frame CreatePAFrame(KeyValuePair<int, string> premiseAddress)
{
Frame frame = new Frame() { Padding = new Thickness(5, 5, 3, 5), HeightRequest = 60 };
StackLayout content = new StackLayout() { Padding = 0 };
content.Orientation = StackOrientation.Horizontal;
Label pAddress = new Label();
pAddress.Text = premiseAddress.Value;
pAddress.Style = Application.Current.Resources["LabelStart"] as Style;
pAddress.HeightRequest = 50;
pAddress.HorizontalOptions = LayoutOptions.StartAndExpand;
Image img = new Image()
{
Source = "rightArrow",
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.CenterAndExpand
};
content.Children.Add(pAddress);
content.Children.Add(img);
frame.Content = content;
var selectAddress = new TapGestureRecognizer();
selectAddress.Tapped += (s, e) =>
{
MessagingCenter.Send(this, "premiseId", premiseAddress.Key);
Navigation.PopAsync();
};
frame.GestureRecognizers.Add(selectAddress);
return frame;
}
And this is how it subscribes to Messaging center:
public Account()
{
MessagingCenter.Subscribe<ContentPage,int>(this, "premiseId", (sender,arg) =>
{
DisplayAlert("Premise Changed", "test", "OK");
selectedPremise = arg;
DisplaySelectedPremiseValues();
});
InitializeComponent();
}
One option could be using a global variable (e.g in App.cs) and setting this variable whenever a list item is tapped:
public static Address TappedAddress;
And before showing the listview reset that variable.

Get label from a stacklayout with a Tap Gesture Recognizer

I would like to know what is the best way to get different label from a stacklayout with a tap gesture. My Stacklayout is a part of a grid.
Seems a good idea but doesn't help to get for example the Text value of my brand name.
Heres the content of my stacklayout:
Image PictureProduct = new Image { Aspect = Aspect.AspectFit };
PictureProduct.Source = FileImageSource.FromUri(...);
Label BrandName = new Label {Text = "HelloWorld"};
Label Description = new Label { Text = "Hello darkness my old friends..."};
Label Price = new Label { Text = "14,99€"};
StackLayout TheStack = new StackLayout { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, HeightRequest = 425 };
TheStack.Children.Add(PictureProduct);
TheStack.Children.Add(BrandName);
TheStack.Children.Add(Description);
TheStack.Children.Add(Price);
var MyTapGesture = new TapGestureRecognizer();
MyTapGesture.Tapped += (sender, e) =>
{
Debug.Write(/*BrandName of product*/);
};
TheStack.GestureRecognizers.Add(MyTapGesture);
I found a solution who's working for the moment.
StackLayout TheStack = new StackLayout { HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, HeightRequest = 425, ClassId = ListProduct[CurrentProd].Sku.ToString(), ClassId = "Something" };
TheStack.Children.Add(PictureProduct);
TheStack.Children.Add(BrandName);
TheStack.Children.Add(Description);
TheStack.Children.Add(Price);
var MyTapGesture = new TapGestureRecognizer();
MyTapGesture.Tapped += (sender, e) =>
{
StackLayout TappedStackId = sender as StackLayout;
Debug.Write("TappedStackId = " + TappedStackId.ClassId);
};
TheStack.GestureRecognizers.Add(MyTapGesture);
You should not attach the TGR to StackLayout, but to every Label. Then, "sender" should say to you which is the "sender"...
You can try something like
PictureProduct.GestureRecognizers.Add(MyTapGesture);
MyTapGesture.Tapped += (sender, e) =>
{
if(sender is PictureProduct){}
};
otherwise, create one TGR for every label
PictureProduct.GestureRecognizers.Add(PictureProductTGR);

Entry control expands beyond StackLayout container

I'm using the following (test) code to dynamically create a Page Content. I'm expecting the Entry control to stay within the StackLayout bounds and clip its large Text value. Somehow this doesn't work like I want.
What am I doing wrong here?
public MyPage() {
InitializeComponent();
var stackMain = new StackLayout() {
Orientation = StackOrientation.Vertical,
Spacing = 2,
BackgroundColor = Color.Yellow
};
Content = stackMain;
Padding = new Thickness(15, Device.OnPlatform(25, 5, 5), 15, 10);
var label = new Label() {
Text = "Test:"
};
stackMain.Children.Add(label);
var stackEntry = new StackLayout() {
Orientation = StackOrientation.Horizontal
};
stackMain.Children.Add(stackEntry);
var entry = new Entry() {
Text = "Blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
IsEnabled = false,
HorizontalOptions = LayoutOptions.FillAndExpand
};
stackEntry.Children.Add(entry);
var button = new Button() {
Text = "Click me"
};
stackEntry.Children.Add(button);
}
What you need is an editor, Entries are one line only, the code below is tested and it fixes the Height by the size of the text:
public class App : Application
{
public App()
{
// The root page of your application
var content = new ContentPage
{
Padding = new Thickness(15, Device.OnPlatform(25, 5, 5), 15, 10),
Title = "test",
Content = new StackLayout
{
Spacing = 2,
BackgroundColor = Color.Yellow,
Children = {
new Label {
Text = "Test:"
},
new Editor {
Text = "Blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
IsEnabled = false,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill
},
}
}
};
MainPage = new NavigationPage(content);
}
}
Hope this helps.
I just solved the same problem on an editor control!
The problem is here Orientation = StackOrientation.Horizontal,
you need to set orientation as StackOrientation.Vertical and it will wrap properly.
Note that I'm using Editor instead of Entry.

xamarin forms: swipe to delete

How can I add Swipe to delete in my note list app.I am using xamarin forms. I have searched in xamarin forms samples but could not find it. I also tried the list view performance options with menuItem etc but I dont know how to adjust that in my code. Can anyone help me with this please?
My code is as follows:
public partial class MyPage
{
List<Note> notes;
string NotesFile {
get {
var documents = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
return System.IO.Path.Combine (documents, "notes.json");
}
}
public MyPage()
{
BuildContent();
LoadNotes ();
ReloadListContents ();
AddNoteButton.Clicked += (sender, args) => {
var note = new Note("typ...");
notes.Add(note);
EditNote(note);
};
NoteListView.ItemTapped += (sender, row) =>
{
NoteListView.SelectedItem = null;
Note note = (Note)row.Item;
EditNote(note);
};
buttonDelete.Clicked += (sender, args) =>{
notes.RemoveAt(0);
DisplayAlert("Delete", "Row deleted", "OK");
};
}
}
MyPage.cs
{
public ListView NoteListView = new ListView ();
public Button AddNoteButton;
public Button buttonDelete;
private void BuildContent()
{
AddNoteButton = new Button
{
Text = "Add New Note",
TextColor = Color.White,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
buttonDelete = new Button
{
Text = "Delete Note ",
TextColor = Color.White,
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center
};
Content = new StackLayout
{
BackgroundColor = Color.Black,
Children = {
new Label {
Text = "Note Taker",
TextColor = Color.White
},
NoteListView,
AddNoteButton,
buttonDelete
}
};
}
Im responding to this question in CS code rather than XAML (My Preferred) if anyone would like the Xaml response please drop a comment below and I'll write the XAML alongside the CS.
So to complete what you have asked in Xamarin.Forms on ListView elements you must first create the ViewCell that you would like to display the data in each cell in the ListView and give it context actions. Here is an example:
public class CustomViewCell : ViewCell
{
public CustomViewCell()
{
//instantiate each element we want to use.
var image = new CircleCachedImage
{
Margin = new Thickness(20, 10, 0, 10),
WidthRequest = App.ScreenWidth * 0.15,
HeightRequest = App.ScreenWidth * 0.15,
Aspect = Aspect.AspectFill,
BorderColor = Color.FromHex(App.PrimaryColor),
BorderThickness = 2,
HorizontalOptions = LayoutOptions.Center
};
var nameLabel = new Label
{
Margin = new Thickness(20, 15, 0, 0),
FontFamily = "Lato",
FontAttributes = FontAttributes.Bold,
FontSize = 17
};
var locationLabel = new Label
{
Margin = new Thickness(20, 0, 0, 5),
FontFamily = "Lato",
FontSize = 13
};
//Create layout
var verticaLayout = new StackLayout();
var horizontalLayout = new StackLayout() { BackgroundColor = Color.White };
//set bindings
nameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
locationLabel.SetBinding(Label.TextProperty, new Binding("Location"));
image.SetBinding(CircleCachedImage.SourceProperty, new Binding("Image"));
//Set properties for desired design
horizontalLayout.Orientation = StackOrientation.Horizontal;
horizontalLayout.HorizontalOptions = LayoutOptions.Fill;
image.HorizontalOptions = LayoutOptions.End;
//add views to the view hierarchy
horizontalLayout.Children.Add(image);
verticaLayout.Children.Add(nameLabel);
verticaLayout.Children.Add(locationLabel);
horizontalLayout.Children.Add(verticaLayout);
//HERE IS THE MOST IMPORTANT PART
var deleteAction = new MenuItem { Text = "Delete", IsDestructive = true }; // red background
deleteAction.Clicked += async (sender, e) => {
//Here do your deleting / calling to WebAPIs
//Now remove the item from the list. You can do this by sending an event using messaging center looks like:
//MessagingCenter.Send<TSender,string>(TSender sender, string message, string indexOfItemInListview)
};
// add to the ViewCell's ContextActions property
ContextActions.Add(deleteAction);
// add to parent view
View = horizontalLayout;
}
}
Now you must do the following to your ListView:
listView = new ListView();
lstView.ItemTemplate = new DataTemplate(typeof(CustomViewCell));
In the same Content Page that you have the ListView you must also subscirbe to the MessagingCenter listening to the same parameters as set in the custom view cell as above. Please read the link provided if you have not used the MessagingCenter before. Inside of this method you must then remove the item from the listview with the index sent to this method.
If anyone needs any further explanations drop a comment below and Ill edit this post.

Categories