I'm navigating from one page to another (using Navigation.PushModalAsync). The first page has a list. The second page has a list view. I want to pass on that list to the second page and then populate a list view with data from that list. How do I go about this?
kind regards
UPDATE:
It appears as though my listview isn't appearing. I tried manually setting the itemsource and the next page is still blank. I have this method:
protected override void OnAppearing()
{
base.OnAppearing();
var listView = new ListView();
//listView.ItemsSource = dataSource;
listView.ItemsSource = new string[]{
"mono",
"monodroid",
"monotouch",
"monorail",
"monodevelop",
"monotone",
"monopoly",
"monomodal",
"mononucleosis"
};
listView.RowHeight = 40;
}
But the next page remains blank with just a red background. To add to this, I don't seem to have the listview.ItemSource.Add() method.
Have a look at the Messaging Center in Xamarin Forms here, which is one option: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/messaging-center/
Or another option is just passing the list in the constructor of the modal you are pushing. In my opinion, using the messaging center is a much cleaner way.
in Page1
List<string> mydata;
var page2 = new Page2(mydata);
Navigation.PushModalAsync(page2);
in Page2
List<string> Data { get; set; }
public Page2(List<string> data) {
this.Data = data;
}
public override void OnAppearing() {
MyListView.ItemsSource = Data;
}
Related
I'm building my first full-scale Xamarin.Forms app and trying to figure out how to keep user input between navigation. After doing some searching online I've read that the default behavior is to completely reload pages each time you navigate, but you can change the default behavior by setting the NavigationCacheMode to true or required, but I've tried to set this attribute in both xaml and C# with no success - it seems like the property is not recognized.
Is there a simple way to make it so that user input does not disappear when navigating between pages? If anyone can show me how to set the NavigationCacheMode that would be great, but I'm also open to any reasonable solution that will keep the user input from disappearing during navigation.
Additional details: My app has a UWP and Android project. I am using a master detail page for navigation. Here is my MenuList_ItemSelected event handler:
private void MenuList_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = (MenuItem)e.SelectedItem;
var title = item.Title;
var page = (Page)Activator.CreateInstance(item.TargetType);
Detail = new NavigationPage(page); //TODO: when menu item is clicked and you're already on that page, the menu should just slide back. (currently it does nothing and stays out).
IsPresented = false;
}
Finally was able to solve this! I adapted this code from a related post which implements a Dictionary that keeps track of the navigation stack:
In the constructor for my Master Detail Page:
public partial class MenuPage : MasterDetailPage
{
Dictionary<Type, Page> menuCache = new Dictionary<Type, Page>();
}
Then in the ItemSelected method:
private void MenuList_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (menuCache.Count == 0)
menuCache.Add(typeof(AttendancePage), Detail);
var item = (MenuItem)e.SelectedItem;
if (item != null)
{
if (menuCache.ContainsKey(item.TargetType))
{ Detail = menuCache[item.TargetType]; }
else
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
menuCache.Add(item.TargetType, Detail);
}
menuList.SelectedItem = null; //solves issue with nav drawer not hiding when same item is selected twice
IsPresented = false;
}
}
I am trying to get this search page in my app to work properly. Right now, it searches through the ListView well, but the ListView does not link to the other pages in the app. Instead, when each ListView element is tapped, it just brings up a blank page. I think I made a mistake in how I structure the DetailPage class, but I am not sure how to fix it.
This is the code for Search.cs.
This is a Xamarin forum post where I have been discussing this problem. Someone has helped me and they have been very helpful so far.
I have been searching around for answers in the MSDN, but I have not been able to figure it out yet. How do I change the value of the DetailPage parameter to so that it actually opens a selected page instead of just a blank page?
This is the DetailPage class.
class DetailPage : ContentPage
{
public DetailPage(pageList page_list)
{
this.page_list = page_list;
}
public pageList page_list { private set; get; }
}
This is where it the DetailPage object detailPage gets its parameter itemSelected. It just opens a blank page, which is not what I want.
listView.ItemTapped += async (sender, args) =>
{
var itemSelected = args.Item as pageList;
if (itemSelected != null)
{
DetailPage detailPage = new DetailPage(itemSelected);
await Navigation.PushAsync(detailPage, true);
}
};
since you know the Type of the page, you can use Activator.CreateInstance to instantiate it
var itemSelected = args.Item as pageList;
if (itemSelected != null)
{
var page = (ContentPage) System.Activator.CreateInstance(itemSelected.fileName);
await Navigation.PushAsync(page, true);
}
Just started with Monodroid and I'm currently working on a ListView.
I got a List added to the ArrayAdapter and i can see my first two items correctly. However when i add a third element to the list, the listview doesnt update. Even though i call notifyDataSetChanged().
private ArrayAdapter<string> la;
private ListView list;
private List<String> dayData = new List<String>();
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
this.SetContentView(Resource.Layout.TestLayout);
dayData.Add(" Test");
dayData.Add(" Test2"); // Theese two elements shows up fine
list = this.FindViewById<ListView>(Resource.Id.menuList);
la = new ArrayAdapter<string>(this, Resource.Layout.list_item, dayData);
list.Adapter = la;
list.TextFilterEnabled = true;
dayData.Add(" Test3"); // This one is not shown
la.NotifyDataSetChanged();
} // OnCreate
Any clues on what i missed?
Found a solution myself at another forum. Somehow the ArrayAdapter does'nt take notice of list changes when using a List. Instead use a Android.Runtime.JavaList.
You can find the discussion here: http://mono-for-android.1047100.n5.nabble.com/Update-ListView-when-dataset-changes-td4757874.html
Works like a charm! :)
I am not entirely sure, but I think that the items are copied into the ArrayAdapter, thus what you need to do is:
la.Add(" Test3");
if you want to keep the list the same you will have to add it to list as well.
try this Add la.notifyDataSetInvalidated(); after la.NotifyDataSetChanged();
I'm not sure how much this will help anyone, but it seems to work fine in my instance.
I have a ViewModel class that keeps all the data I update within the App and trigger a "Collection Updated" action when a collection changes.
// All within ViewModel.cs
private Action SearchResultsUpdated;
private List<SearchResult> m_oSearchResults;
Public List<SearchResult> SearchResults
{
get
{
if (m_oSearchResults == null)
m_oSearchResults = new List<SearchResult> ();
return m_oSearchResults;
}
set
{
if (value != m_oSearchResults)
{
m_oSearchResults = value;
//
// Fire update event
if (SearchResultsUpdated != null)
SearchResultsUpdated ();
}
}
}
I then add a handler for this event within the adapter class.
// All within SearchResultsAdapter.cs
public class SearchResultsAdapter : BaseAdapter<SearchResult>
{
.
.
// Constructor
public SearchResultsAdapter (Activity oContext)
: base ()
{
// Add handler for list refresh
ViewModel.SearchResultsUpdated += NotifyDataSetChanged;
//
m_oContext = oContext;
}
}
Within the adapter I use the collection ViewModel.SearchResults as the data context for the list view. Hope that helps and is thorough enough for everyone to understand.
To update the ListView
private ListView lvAnuncios = null;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
this.lvAnuncios = this.FindViewById<ListView>(Resource.Id.MisAnuncios_lvAnuncios);
}
private void ReloadListView()
{
if (this.lvAnuncios.Adapter != null)
{
this.lvAnuncios.Adapter.Dispose();
this.lvAnuncios.Adapter = null;
}
//Class that inherits de ArrayAdapter
this.lvAnuncios.Adapter = new adAnuncio(this, Resource.Layout.FilaListViewAnuncio, csVariable.objUsr.lstAnuncios);
}
I have a Form with a listview. After calling Form.Show I need to update my listview. However, after Form.Show is called regardless of my listview code, it comes up empty, no columns, no data. If I move the Form.Show till after my listview code, the listview shows correctly.
Here is my listview code :
private void InitializeListView()
{
_snapshotList.BeginUpdate();
_snapshotList.Items.Clear();
foreach (ISnapshot snapshot in _snapshots)
{
string comment = InstanceFactory<ProjectRecoveryService>.Instance.RetrieveCommentsforSnapshot(snapshot);
string[] sub = new string[] { snapshot.Name, snapshot.Version.ToString(), snapshot.CreatedDate.ToString(), comment };
ListViewItem item = new ListViewItem(sub);
item.Tag = snapshot;
this._snapshotList.Items.Add(item);
}
_snapshotList.EndUpdate();
this._snapshotList.Refresh();
}
A side note, I have another Form that is very similar but has a TreeView that someone else has extended which works as desired.
Any thoughts?
EDIT 1
This form needs be a single instance. After reading this post, my Form.Show code is structured like this :
public static RestoreSnapshotDialog GetInstance()
{
if (_dialog == null)
{
_dialog = new RestoreSnapshotDialog();
_dialog.Show(Control.FromHandle(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle));
}
else
{
_dialog.BringToFront();
}
return _dialog;
}
On a FormClosed event I set _dialog = null.
You have to handle Form.Shown event to update the listview.
The only solution I could find was to call the Form.Show() after my listview was fully populated. So I create my own Form.Show by overriding Form.Show.
public new void Show()
{
if (_showdialog)
{
_dialog.Show(Control.FromHandle(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle));
}
else
{
_dialog.BringToFront();
}
}
Calling this method after my listview solves my problem. However, all my other dialogs (not using listview) work as expected with the code from the original post. Thanks to Hans Passant for leading me to this solution.
I have an 3 tier application (DAL, BBL, UI)
BBL at the moment do Nothing just a pass-thru
I have a grid view and for simplicity's sake one text box(TB) and one drop down list(DDL).
and Two submit buttons.
(I changed my Custom Class to Object. just for this example)
First Submit button adds the TB.text & DDL.SelectedValue to a Object X in the UI.
the BBL takes that object X to adds it to a List(X) in the BBL.
Then the BBL should populate the Gridview with the List(X). (with ajax partial page load)
the second Submit should send the full List(X) to the database.
The problem im having is when I click the first Submit(the local) I dont get new Rows just keep over writing the same row. what am I Missing?
in the UI class
private businesslogic blogic = new businesslogic();
protected void B1_local_Click(object sender, EventArgs e)
{
object x = new object();
x.id = Convert.ToInt32(TB_1.Text);
x.var1 = Convert.ToInt32(DDL_1.SelectedValue);
blogic.addrowtolist(x);
Gridview1.DataSource = blogic.grablist();
Gridview1.Databind();
}
in the BBL class
public List<object> locallist = new List<object>();
public void addrowtolist(object x)
{
locallist.Add(x);
}
public List<object> grablist()
{
return locallist;
}
With every postback, you're loading a new BL with a new (empty) List. To see your List grow, you're going to need to save it somewhere that persists (doesn't disappear) between one request and the next.
I would recommend putting your List in a Session key
Session["items"] = blogic.locallist;
and then pulling it out and sending it to a second BL constructor on postback. This is probably simplest, but not always the correct approach.
http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx