MonoTouch.Dialog : Advanced Editing - xamarin.ios

I'm trying to put together a detail view that is editable, similar to the iPhone default contacts app.
I have a TableView of contacts and I activate an editable detail view when a cell is selected:
public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
var editingSection = new Section ("Entity") {
new StringElement ("First name", "enter", _entity.FirstName),
new StringElement ("Last name", "enter", _entity.LastName)
};
var root = new RootElement("Entity Entry") {
editingSection
};
var entityEdit = new EntityEdit (root, true);
ConfigEdit (entityEdit);
dvc.ActivateController(entityEdit);
}
void ConfigEdit (DialogViewController dvc)
{
dvc.NavigationItem.RightBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Edit, delegate {
dvc.TableView.SetEditing (true, true);
ConfigDone (dvc);
});
}
void ConfigDone (DialogViewController dvc)
{
dvc.NavigationItem.RightBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Done, delegate {
dvc.TableView.SetEditing (false, true);
ConfigEdit (dvc);
});
}
The behavior that I want to change is in the ConfigEdit method. When I first show the view, the elements in the editing section should be StringElements. When I switch to edit mode, the elements should change to entry Elements because I want the ability to delete the row, or edit the text inside the element.
Is this possible? Is there a better approach to showing read-only elements until edit mode has been set?

You have a couple of options:
a. You can just change the RootElement with an updated RootElement, or update the individual cells with new cells of the proper type of element to get the desired effect. You could do this by parametrizing your creation:
RootElement CreateRoot (bool editable)
{
return new RootElement (...) {
CreateEditableElement ("foo", bar, editable)
}
}
Element CreateEditableElement (string caption, string content, bool editable)
{
return editable ? EntryElement (caption, content) : StringELement (caption, content)
}
Then you need to call ReloadData after the user has tapped the "Edit" button.
The other thing that you could do is to create a new Element that can switch states based on this information. My blog has a tutorial on how to create new elements:
http://tirania.org/monomac/archive/2011/Jan-18.html

Based on Miguel's answer, here is what I did:
public partial class AppDelegate
{
public void DemoAdvancedEditing ()
{
var root = new RootElement ("Todo list") {
new Section() {
new StringElement ("1", "Todo item 1"),
new StringElement ("2","Todo item 2"),
new StringElement ("3","Todo item 3"),
new StringElement ("4","Todo item 4"),
new StringElement ("5","Todo item 5")
}
};
var dvc = new AdvancedEditingDialog (root, true);
AdvancedConfigEdit (dvc);
navigation.PushViewController (dvc, true);
}
void AdvancedConfigEdit (DialogViewController dvc)
{
dvc.NavigationItem.RightBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Edit, delegate {
// Activate editing
// Switch the root to editable elements
dvc.Root = CreateEditableRoot(dvc.Root, true);
dvc.ReloadData();
// Activate row editing & deleting
dvc.TableView.SetEditing (true, true);
AdvancedConfigDone(dvc);
});
}
void AdvancedConfigDone (DialogViewController dvc)
{
dvc.NavigationItem.RightBarButtonItem = new UIBarButtonItem (UIBarButtonSystemItem.Done, delegate {
// Deactivate editing
dvc.ReloadData();
// Switch updated entry elements to StringElements
dvc.Root = CreateEditableRoot(dvc.Root, false);
dvc.TableView.SetEditing (false, true);
AdvancedConfigEdit (dvc);
});
}
RootElement CreateEditableRoot (RootElement root, bool editable)
{
var rootElement = new RootElement("Todo list") {
new Section()
};
foreach (var element in root[0].Elements) {
if(element is StringElement) {
rootElement[0].Add(CreateEditableElement (element.Caption, (element as StringElement).Value, editable));
} else {
rootElement[0].Add(CreateEditableElement (element.Caption, (element as EntryElement).Value, editable));
}
}
return rootElement;
}
Element CreateEditableElement (string caption, string content, bool editable)
{
if (editable) {
return new EntryElement(caption, "todo", content);
} else {
return new StringElement(caption, content);
}
}
}

Related

How to implement UICollectionView - XAMARIN.IOS

I'm trying to use UICollectionView but I can't find any samples that I can take advantage of. I needed the UICollectionView by code (without using swift/storyboard/forms). Could you give me a really simple example? For example 2 lines with 2 columns please? Basic stuff just to try to understand how I can implement it.
Thank you
You can refer to Collection Views in Xamarin.iOS doc to check how to use Collection View with Code .And here I will show a sample code to explain how to implement it .
Could you give me a really simple example? For example 2 lines with 2 columns please?
First , need to create a GridLayout :
public class GridLayout : UICollectionViewFlowLayout
{
public GridLayout ()
{
}
public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
{
return true;
}
public override UICollectionViewLayoutAttributes LayoutAttributesForItem (NSIndexPath path)
{
return base.LayoutAttributesForItem (path);
}
public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
{
return base.LayoutAttributesForElementsInRect (rect);
}
}
Then you can init the Collection View in ViewDidLoad :
static NSString animalCellId = new NSString("AnimalCell");
List<IAnimal> animals;
animals = new List<IAnimal>();
for (int i = 0; i < 2; i++)
{
animals.Add(new Monkey());
}
// Perform any additional setup after loading the view, typically from a nib.
UICollectionView collectionView = new UICollectionView(new CGRect(0, 0, UIScreen.MainScreen.Bounds.Size.Width, 300), new GridLayout());
collectionView.RegisterClassForCell(typeof(AnimalCell), animalCellId);
collectionView.BackgroundColor = UIColor.Blue;
collectionView.DataSource = new MyCollectionViewDataDelegate(animals);
View.AddSubview(collectionView);
Here you also need to creat a Custom Cell for your needs , this can be modified by yourself :
public class AnimalCell : UICollectionViewCell
{
UIImageView imageView;
[Export("initWithFrame:")]
public AnimalCell(CGRect frame) : base(frame)
{
BackgroundView = new UIView { BackgroundColor = UIColor.Orange };
SelectedBackgroundView = new UIView { BackgroundColor = UIColor.Green };
ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
ContentView.Layer.BorderWidth = 2.0f;
ContentView.BackgroundColor = UIColor.White;
ContentView.Transform = CGAffineTransform.MakeScale(0.8f, 0.8f);
imageView = new UIImageView(UIImage.FromBundle("placeholder.png"));
imageView.Center = ContentView.Center;
imageView.Transform = CGAffineTransform.MakeScale(0.7f, 0.7f);
ContentView.AddSubview(imageView);
}
public UIImage Image
{
set
{
imageView.Image = value;
}
}
[Export("custom")]
void Custom()
{
// Put all your custom menu behavior code here
Console.WriteLine("custom in the cell");
}
public override bool CanPerform(Selector action, NSObject withSender)
{
if (action == new Selector("custom"))
return true;
else
return false;
}
}
The MyCollectionViewDataDelegate also need to be created:
public class MyCollectionViewDataDelegate : UICollectionViewDataSource
{
private List animals;
public MyCollectionViewDataDelegate(List<IAnimal> animals)
{
this.animals = animals;
}
public override nint NumberOfSections(UICollectionView collectionView)
{
return 2;
}
public override nint GetItemsCount(UICollectionView collectionView, nint section)
{
return animals.Count;
}
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var animalCell = (AnimalCell)collectionView.DequeueReusableCell(animalCellId, indexPath);
var animal = animals[indexPath.Row];
animalCell.Image = animal.Image;
return animalCell;
}
}
You can find that animalCell should be registed when init Collection View .
Then effect :
This is the sample link for reference .

How to implement Custom Suggestions in SearchView from fragment

i have a view pager with 3 fragment one of the fragment
have searchview widget and i get to know that i can,t implement the standard search interface so i implement some thing like this but how to implement Custom Suggestions in SearchView
public class LoaderCursor extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getFragmentManager();
// Create the list fragment and add it as our sole content.
if (fm.findFragmentById(android.R.id.content) == null) {
CursorLoaderListFragment list = new CursorLoaderListFragment();
fm.beginTransaction().add(android.R.id.content, list).commit();
}
}
public static class CursorLoaderListFragment extends ListFragment
implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
// If non-null, this is the current filter the user has provided.
String mCurFilter;
#Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText("No phone numbers");
// We have a menu item to show in action bar.
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2, null,
new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
#Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Place an action bar item for searching.
MenuItem item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
public boolean onQueryTextChange(String newText) {
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(0, null, this);
return true;
}
#Override public boolean onQueryTextSubmit(String query) {
// Don't care about this.
return true;
}
#Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i("FragmentComplexList", "Item clicked: " + id);
}
// These are the Contacts rows that we will retrieve.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ Contacts.DISPLAY_NAME + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
}

Add action on ObservableList item in javafx

I am using javafx to make a ListView in which add Observable List which contains buttons.
I want to add action on each buttons in this lists.Any help...
ObservableList videoLists = null;
if (listView.getSelectionModel().getSelectedItem().equals("class 8")) {
classTitleID.setText("class 8 video lists");
File physicsFolder = new File("D:\\videos\\physics");
File[] listOfFiles = physicsFolder.listFiles();
videoLists = FXCollections.observableArrayList();
for (File file : listOfFiles) {
if (file.isFile()) {
videoLists.add(new Button(file.getName()));
physicsListview.setItems(videoLists);
}
}
}
simply do
for (File file : listOfFiles) {
if (file.isFile()) {
Button button = new Button(file.getName());
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
//your action
}
});
videoLists.add(button);
physicsListview.setItems(videoLists);
}
}
It's generally a bad idea to have Node subclasses as the data type in ListViews (or TableViews, ComboBoxes, etc): it breaks MVC. Make your ListView a ListView<File> and use a cellFactory to show the button in the ListView cells. You can set the action handler there.
ListView<File> physicsListview = new ListView<>();
ObservableList<File> videoLists = FCollections.observableArrayList();
//...
for (File file : listOfFiles) {
if (file.isFile()) {
videoLists.add(file);
}
}
physicsListview.setItems(videoLists);
physicsListview.setCellFactory(new Callback<ListView<File>, ListCell<File>>() {
#Override
public ListCell<File> call(ListView<File>()) {
final Button button = new Button();
return new ListCell<File>() {
#Override
public void updateItem(final File item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
button.setText(item.getName());
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// handle action.
// You can access the File object item here if needed
}
});
setGraphic(button);
}
}
};
});
});

RadioGroup returning selected value

I have a RadioGroup I created:
Root = new RootElement ("Club 1") {
new Section ("Club Members"){
new StringElement ("P1", "Kyle"),
new StringElement ("P2", "Matt"),
new RootElement("Members", new RadioGroup(0))
{
CreateRoot()
}
}
The RootElement above need to the display the value selected from the RadioGroup.
RootElement CreateRoot ()
{
StringElement se = new StringElement (String.Empty);
MyRadioElement.OnSelected += delegate(object sender, EventArgs e) {
se.Caption = (sender as MyRadioElement).Caption;
var root = se.GetImmediateRootElement ();
root.Reload (se, UITableViewRowAnimation.Fade);
};
return new RootElement (String.Empty, new RadioGroup (0)) {
new Section ("Select Member") {
new MyRadioElement ("No Member Selected"),
new MyRadioElement ("Member 1"),
new MyRadioElement ("Member 2"),
new MyRadioElement ("Member 3")
}
};
}
I have an outside class:
class MyRadioElement : RadioElement {
public MyRadioElement (string s) : base (s) {}
public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
base.Selected (dvc, tableView, path);
var selected = OnSelected;
if (selected != null)
selected (this, EventArgs.Empty);
}
static public event EventHandler<EventArgs> OnSelected;
}
How do I get the selected value to display back on the parent root element?
I was not deactivating the controller.
class MyRadioElement : RadioElement {
public MyRadioElement (string s) : base (s) {}
public override void Selected (DialogViewController dvc, UITableView tableView, NSIndexPath path)
{
base.Selected (dvc, tableView, path);
var selected = OnSelected;
if (selected != null)
selected (this, EventArgs.Empty);
dvc.DeactivateController(true);
}
static public event EventHandler<EventArgs> OnSelected;
}

MonoTouch.Dialog how to get data from dialog

I'm a beginner in MonoTouch and MonoTouch.Dialog.
I am trying to use MT Dialog but I cannot understand how to get data in and out.
Let's say I have Event class:
class Event {
bool type {get;set;}
string name {get;set;}
}
And I want to edit it using this dialog definition:
return new RootElement ("Event Form") {
// string element
new Section ("Information"){
new EntryElement ("Name", "Name of event", ""),
new RootElement ("Type", new RadioGroup (0)){
new Section (){
new RadioElement ("Concert"),
new RadioElement ("Movie"),
new RadioElement ("Exhibition"),
new RadioElement ("Sport")
}
}
},
How can I pass data to and from this form? (using low-level API not Reflection which supports binding)
Very easy, assign the intermediate values to variables:
Section s;
SomeElement e;
return new RootElement ("Foo") {
(s = new Section ("...") {
(e = new StringElement (...))
})
};
You can do something like this:
//custom class to get the Tapped event to work in a RadioElement
class OptionsRadioElement: RadioElement
{
public OptionsRadioElement(string caption, NSAction tapped): base(caption)
{
Tapped += tapped;
}
}
//Custom Controller
public class MyController: DialogViewController
{
private readonly RadioGroup optionsGroup;
private readonly EntryElement nameField;
public MyController(): base(null)
{
//Note the inline assignements to the fields
Root = new RootElement ("Event Form") {
new Section ("Information"){
nameField = new EntryElement ("Name", "Name of event", ""),
new RootElement ("Type", optionsGroup = new RadioGroup (0)){
new Section (){
new OptionsRadioElement("Concert", OptionSelected),
new OptionsRadioElement("Movie", OptionSelected),
new OptionsRadioElement("Exhibition", OptionSelected),
new OptionsRadioElement("Sport", OptionSelected)
}
}
};
}
private void OptionSelected()
{
Console.WriteLine("Selected {0}", optionsGroup.Selected);
}
public void SetData(MyData data)
{
switch(data.Option)
{
case "Concert:
optionsGroup.Selected = 0;
break;
case "Movie":
optionsGroup.Selected = 1;
break;
//And so on....
default:
optionsGroup.Selected = 0;
break;
}
nameField.Value = data.Name;
ReloadData();
}
}

Resources