I am new to mono for android. I am trying to make a simple checkbox list where I can select my candidates, press a button to insert them to Database. All is fine till here but the problem is with loading my checked values. My checkboxes are always unchecked even if i explicitly put this.Checked = true;
here is my code:
Loading listview:
var CandidatesList = FindViewById<ListView>(Resource.Id.lstVotingCandidates);
CandidatesVoteAdapter cva = new CandidatesVoteAdapter(this, MAE.Code.Utilities.CandidatesInfo.CurrentList);
CandidatesList.ChoiceMode = ChoiceMode.Multiple;
CandidatesList.Adapter = cva;
Adapter:
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView; // re-use an existing view, if one is available
if (view == null) // otherwise create a new one
{
view = new Views.CandidateVoteItemView(context, items[position]);
}
return view;
}
View:
class CandidateVoteItemView : CheckBox
{
public MAE.MAEService.Candidate Candidate { get; protected set; }
public CandidateVoteItemView(Context context, MAE.MAEService.Candidate candidate) : base(context)
{
this.Text = candidate.FirstName; //Working
this.Checked = true;// (candidate.isChecked == 1) ? true : false;//Not Working
}
}
You can try this approach:
lv.SetItemChecked(1, true);
Taken from official xamarin site and check section 2.2
Related
I spent so much time for discover how to implement TreeView in Android Xamarin, but unlucky seem not have any example say about that.
I tried to use ExpandableListView but it only support to level 2 category. I need someone will have any guide to through this content or some example say about that.
The purpose is explore the folders on server!
Thanks you so much.
The purpose is explore the folders on server!
You can use Binding Library to import some java library for example like AndroidTreeView.
For example, I created an .aar lib from this project. And then code for example like this:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
//create root
TreeNode root = TreeNode.InvokeRoot();
TreeNode parent = new TreeNode("parent");
TreeNode child0 = new TreeNode("ChildNode0");
TreeNode child1 = new TreeNode("ChildNode1");
TreeItem item = new TreeItem() { text = "abc" };
TreeNode child10 = new TreeNode(item).SetViewHolder(new MyHolder(this));
child1.AddChild(child10);
parent.AddChildren(child0, child1);
root.AddChild(parent);
AndroidTreeView atv = new AndroidTreeView(this, root);
LinearLayout rootlayout = FindViewById<LinearLayout>(Resource.Id.rootlayout);
rootlayout.AddView(atv.View);
rootlayout.Invalidate();
}
The TreeItem is created like this:
public class TreeItem : Java.Lang.Object
{
public string text;
}
And MyHolder is like this:
public class MyHolder : TreeNode.BaseNodeViewHolder
{
private Context mcontext;
public MyHolder(Context context) : base(context)
{
mcontext = context;
}
public override View CreateNodeView(TreeNode p0, Java.Lang.Object p1)
{
var inflater = LayoutInflater.FromContext(mcontext);
var view = inflater.Inflate(Resource.Layout.itemview, null, false);
TextView tv = view.FindViewById<TextView>(Resource.Id.itemtv);
var item = p1 as TreeItem;
tv.Text = item.text;
return view;
}
}
Here is the demo, you can find the .aar lib there.
I am trying to implement instant search functionality using edittext.I have just binded the json array response to listview and added edittext at top of listview and trying to filter or search data in listview as user starts to type in edittext below code is used.Please help me. Any kind of suggestion,guidence and help is appreciated.
MainActivity.cs
SetContentView(Resource.Layout.HomeScreen);
tableItems = new List<TableItem>();
var client = new RestClient("http://azurewebsites.net/");
var request = new RestRequest("Service/regionSearch", Method.POST);
request.RequestFormat = DataFormat.Json;
tableItems = client.Execute<List<TableItem>>(request).Data;
listView.Adapter = new HomeScreenAdapter(this, tableItems);
region = FindViewById<TextView> (Resource.Id.viewtext);
area= FindViewById<TextView> (Resource.Id.viewtext2);
_filterText = FindViewById<EditText>(Resource.Id.search);
listView = FindViewById<ListView>(Resource.Id.listView);
_filterText.TextChanged += (object sender, Android.Text.TextChangedEventArgs e) => {
// filter on text changed
var searchTerm = _filterText.Text;
};
listView.ItemClick += OnListItemClick;
}
protected void OnListItemClick(object sender, Android.Widget.AdapterView.ItemClickEventArgs e)
{
var listView = sender as ListView;
var t = tableItems[e.Position];
// var clickedTableItem = listView.Adapter[e.Position];
Android.Widget.Toast.MakeText(this, clickedTableItem.DDLValue, Android.Widget.ToastLength.Short).Show();
}
HomeScreenAdapter.cs
public class HomeScreenAdapter : BaseAdapter<TableItem> {
List<TableItem> items;
Activity context;
public HomeScreenAdapter(Activity context, List<TableItem> items)
: base()
{
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override TableItem this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
// TableItem item = items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.DDLValue;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.areaMsg;
return view;
}
}
It looks like you're pretty close. The last step is to use the searchTerm to filter out the results in tableItems. The easiest way to do this is to simply create a new HomeScreenAdapter with the filtered list, and set that as the ListView.Adapter. Check out this example code that implements: getting the search text, filtering all of your TableItem instances, and then giving the ListView a new Adapter.
_filterText.TextChanged += (object sender, Android.Text.TextChangedEventArgs e) => {
// filter on text changed
var searchTerm = _filterText.Text;
var updatedTableItems = tableItems.Where(
// TODO Fill in your search, for example:
tableItem => tableItem.Msg.Contains(searchTerm) ||
tableItem.DDLValue.Contains(searchTerm)
).ToList();
var filteredResultsAdapter = new HomeScreenAdapter(this, updatedTableItems);
listView.Adapter = filteredResultsAdapter;
};
Notice the TODO inside of the Where clause. I have no idea how you want to search on your TableItem but once you write your Where clause, this should do what you want.
It looks like your TableItem class is something like this (for reference):
public class TableItem {
public int Id {get; set;}
public string DDLValue {get; set;}
public string Msg {get; set;}
public int Status {get; set;}
}
I try to show a GridView in a ListView. I want to show images grouped by some properties.
My Listview (Info: I removed all layout-options in following snippets (better readable):
<Mvx.MvxListView
android:id="#+id/albumdetail_imagelist"
local:MvxBind="ItemsSource Data.GroupedPictures;"
local:MvxItemTemplate="#layout/list_albumdetail" />
Then the list_albumdetail layout file:
<LinearLayout>
<TextView android:id="#+id/albumdetailitem_header" />
<Mvx.MvxGridView
android:id="#+id/albumdetailitem_imagegrid"
android:numColumns="3"
android:stretchMode="columnWidth"
local:MvxItemTemplate="#layout/list_phonepicture" />
</LinearLayout>
This MvxGridView above works perfectly when it stands alone (without a ListView as parent. The ListView is just to show a header.
Here is my Adapter to show the Listview:
public class AlbumDetailAdapter : BasePictureSectionAdapter
{
private readonly Activity _context;
public AlbumDetailAdapter(Activity context, IMvxAndroidBindingContext bindingContext, bool hideheader = false)
: base(context, bindingContext, hideheader)
{
_context = context;
}
protected override View GetView(int position, View convertView, ViewGroup parent, int templateId)
{
var keyitem = GetRawItem(position) as KeyedList<string, PictureDetailDataModel>;
if (keyitem == null) return base.GetView(position, convertView, parent, templateId);
AlbumDetailViewHoler holder = null;
if (convertView == null)
{
// HERE CRASHS THE APP
convertView = _context.LayoutInflater.Inflate(templateId, parent, false);
}
else
{
holder = (AlbumDetailViewHoler)convertView.Tag;
}
if (holder == null)
{
holder = new AlbumDetailViewHoler
{
Header = convertView.FindViewById<TextView>(Resource.Id.albumdetailitem_header),
GridView = convertView.FindViewById<SpecialGridView>(Resource.Id.albumdetailitem_imagegrid)
};
holder.GridView.FastScrollEnabled = false;
holder.GridView.Adapter = new PhonePictureAdapter(_context, BindingContext, 120);
convertView.Tag = holder;
}
// Set header text
holder.Header.Text = keyitem.Key;
// Set itemsource
holder.GridView.ItemsSource = keyitem.Values;
return convertView;
}
private class AlbumDetailViewHoler : BaseSectionViewHolder
{
public SpecialGridView GridView { get; set; }
}
}
The app crashs with the following exception:
bindingContext is null during MvxAdapter creation - Adapter's should
only be created when a specific binding context has been placed on the
stack"
I have no idea whats going wrong. Without the inner GridView it works perfectly, so the BindingContext can't be null. Is there a better way to achive this? (without an external library)? Or whats going wrong? Thanks
Just for others with same problems, I answer my own question.
The problem was, that I tried to infalte the layout from the normal context. With MvvmCross I need to do that with the BindingContext:
convertView = BindingContext.BindingInflate(templateId, parent, false);
This BindingContext is a IMvxAndroidBindingContext and is set by the constructor.
I want add search logic for my application (IOS8). I have simple MvxTableViewController and display my data by UITableViewSource. Here is:
...controller:
MvxViewFor(typeof(MainViewModel))]
partial class MainController : MvxTableViewController
{
public MainController(IntPtr handle) : base(handle) { }
public override void ViewDidLoad()
{
base.ViewDidLoad();
// make background trasnsparent page
this.View.BackgroundColor = UIColor.Clear;
this.TableView.BackgroundColor = UIColor.Clear;
this.NavigationController.NavigationBar.BarStyle = UIBarStyle.Black;
this.SetBackground ();
(this.DataContext as MainViewModel).PropertyChanged += this.ViewModelPropertyChanged;
}
private void SetBackground()
{
// set blured bg image
}
private void ViewModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var viewModel = this.ViewModel as MainViewModel;
if (e.PropertyName == "Title")
{
this.Title = viewModel.Title;
}
else if (e.PropertyName == "Topics")
{
var tableSource = new TopicTableViewSource(viewModel.Topics);
tableSource.TappedCommand = viewModel.NavigateToChildrenPageCommand;
this.TableView.Source = tableSource;
this.TableView.ReloadData();
}
}
I read about search in IOS and choosed UISearchController for IOS8 app. But I don't understand, how I can add this controller to my view :(
I found sample from Xamarin (TableSearch) - but they don't use UITableViewSource and I don't understand what I should do with this.
I tried add controller:
this.searchController = new UISearchController (this.searchTableController)
{
WeakDelegate = this,
DimsBackgroundDuringPresentation = false,
WeakSearchResultsUpdater = this,
};
this.searchController.SearchBar.SizeToFit ();
this.TableView.TableHeaderView = searchController.SearchBar;
this.TableView.WeakDelegate = this;
this.searchController.SearchBar.WeakDelegate = this;
what should I do in this.searchTableController? Do I need move my display logic there?
Yes. The "searchTableController" should be responsible for the presentation of search results.
Here is the test project (native, not xmarin) which help you understand.
The searchController manages a "searchBar" and "searchResultPresenter". His not need add to a view-hierarchy of the carrier controller. When user starts typing a text in the "searchBar" the "SearchController" automatically shows your SearchResultPresenter for you.
Steps:
1) Instantiate search controller with the SearchResultsPresenterController.
2) When user inputs text in the search-bar you should invoke a your own service for the search. Below a sample of code..
#pragma mark - UISearchResultsUpdating
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
NSString *searchString = searchController.searchBar.text;
if (searchString.length > 1)
{
// TODO - call your service for the search by string
// this may be async or sync
// When a data was found - set it to presenter
[self.searchResultPresenter dataFound:<found data>];
}
}
3) In the search presenter need to reload a table in the method "dataFound:"
- (void)dataFound:(NSArray *)searchResults
{
_searchResults = searchResults;
[self.tableView reloadData];
}
Here are some advice on how to use the UISearchController with Xamarin.iOS.
Create a new class for the results table view subclassing UITableViewSource. This is gonna be the view responsible of displaying the results. You need to make the items list of that table view public.
public List<string> SearchedItems { get; set; }
In your main UIViewController, create your UISearchController and pass your result table view as an argument. I added some extra setup.
public UISearchController SearchController { get; set; }
public override void ViewDidLoad ()
{
SearchController = new UISearchController (resultsTableController) {
WeakDelegate = this,
DimsBackgroundDuringPresentation = false,
WeakSearchResultsUpdater = this,
};
SearchController.SearchBar.SizeToFit ();
SearchController.SearchBar.WeakDelegate = this;
SearchController.HidesNavigationBarDuringPresentation = false;
DefinesPresentationContext = true;
}
The best way to add the search bar to your UI in term of user experience, in my opinion, is to add it as a NavigationItem to a NavigationBarController.
NavigationItem.TitleView = SearchController.SearchBar;
Add methods to perform the search in the main UIViewController:
[Export ("updateSearchResultsForSearchController:")]
public virtual void UpdateSearchResultsForSearchController (UISearchController searchController)
{
var tableController = (UITableViewController)searchController.SearchResultsController;
var resultsSource = (ResultsTableSource)tableController.TableView.Source;
resultsSource.SearchedItems = PerformSearch (searchController.SearchBar.Text);
tableController.TableView.ReloadData ();
}
static List<string> PerformSearch (string searchString)
{
// Return a list of elements that correspond to the search or
// parse an existing list.
}
I really hope this will help you, good luck.
i have a window that shows a list of entities and i want to edit the selecteitem of gridview in a new window (Not in grid). when i submit my form no error occurred but entity have no changes in database! please help me.
in top of my list window code behind:
private ObservableCollection<Employee> AllEmployeesData { get; set; }
private ListCollectionView View;
and in window_loaded i use this method for fetch data:
public void LoadAllEmployees()
{
IEnumerable<Employee> data = null;
using (ArchiveEntities db = new ArchiveEntities())
{
data = db.Employees.Include("Department");
this.AllEmployeesData = new ObservableCollection<Employee>(data);
}
CollectionViewSource employeeSource = (CollectionViewSource)this.FindResource("AllEmployeesDataSource");
employeeSource.Source = this.AllEmployeesData;
this.View = (ListCollectionView)employeeSource.View;
}
Editbutton click event:
EditEmployeeView win = new EditEmployeeView();
View.EditItem(SelectedEmployee);
win.DataContext = SelectedEmployee;
if ((bool)win.ShowDialog())
{
using (ArchiveEntities db = new ArchiveEntities())
{
Employee employee = db.Employees.Single(x => x.Id == SelectedEmployee.Id);
db.Employees.ApplyCurrentValues(employee);
db.SaveChanges();
View.CommitEdit();
}
}
else
{
View.CancelEdit();
}
all of the above code is in my first window (window that shows a list of entities).
and in my second window (window for edit selected item of a first window):
submitbutton click event:
DialogResult = true;
Close();
my problem is: when i submit edit form no error occurred but data dont save in database and when i cancel edit form i get this error:
InvalidOperationException was unhandled: CancelEdit is not supported
for the current edit item.
Go away from "using" in datacontext is a really bad approach for entity framework!
If you close your datacontext before save, all entity result disconnected and save as no resut.
Try this way, use a class level context, stay connected and use all power of entityframework
public mainClass{
private ArchiveEntities db;
private ObservableCollection<Employee> allEmployeesData;
private Employee selctedEmplyee;
// property in binding
public ObservableCollection<Employee> AllEmployeesData { get{return allEmployeesData;} set{allEmployeesData=value; onPropertyChanged("AllEmployeesData"); }
public Employee SelctedEmplyee { get{return selctedEmplyee;} set{selctedEmplyee=value; onPropertyChanged("SelctedEmplyee"); }
mainWindow (){ //Constructor
db=new ArchiveEntities();
}
private void onedit(){
new detailWindow(SelectedEmployee).ShowDialog();
//reload from db, upadte current element if modified in the detail window
SelectedEmployee = db.Employees.Single(x => x.Id == SelectedEmployee.Id);
}
//no need to save in main window (is only for view)
}
public class detailWindow(){
private ArchiveEntities db;
private Employee selctedEmplyee;
//employee to modify
public Employee SelctedEmplyee { get{return selctedEmplyee;} set{selctedEmplyee=value; onPropertyChanged("SelctedEmplyee"); }
public detailWindow(Employee SelectedEmployee){
db=new ArchiveEntities; // a new indipendent context
SelectedEmployee = db.Employees.Single(x => x.Id == SelectedEmployee.Id);
}
public void onSave(){
db.SaveChanges(); //effect only in SelectedEmployee
// if you don'save main window data will not change
}
}
why you use View.EditItem,View.CommitEdit and View.CancelEdit? all you need is your win.DataContext = SelectedEmployee. what i dont get is when you set your new edited data to your entity?
using (ArchiveEntities db = new ArchiveEntities())
{
Employee employee = db.Employees.Single(x => x.Id == SelectedEmployee.Id);
db.Employees.ApplyCurrentValues(employee);
db.SaveChanges();
View.CommitEdit();
}
you get the employee from db but you dont apply the edited data from SelectedEmployee to your employee. or do i miss something?
the SelectedEmployee is a entity from your db
data = db.Employees.Include("Department");
this.AllEmployeesData = new ObservableCollection<Employee>(data);
so why you dont use it and save it back to db?
db.SaveChanges(SelectedEmployee );
Employee class must implement IEditableObject
you can see an example here : https://msdn.microsoft.com/en-us/library/system.componentmodel.ieditableobject.aspx
After this implementation, it should work as expected