Save swipe item to firebase realtime in xamarin form - firebase-realtime-database

I want to save the swipe selected to firebase.
but idk how to do it and cant find any solution to internet.
This is my codes in swipe view
<SwipeView x:Name="swipe_orderstatus">
<SwipeView.RightItems >
<SwipeItems >
<SwipeItem Text="Received"
BackgroundColor="#73a9c2"
Invoked="SwipeItem_Invoked_1"
/>
</SwipeItems>
</SwipeView.RightItems>
</SwipeView>
then this is what I've tried in code behind.
private void SwipeItem_Invoked_1(object sender, EventArgs e)
{
// string swipeIt
// string swipeViewItem= swipe var picker = (Picker)sender;
// int selectedIndex = picker.SelectedIndex;
var swipeView = (SwipeView)sender;
string swipeViewItem= swipeView
}
thank you in advance.

you can get the selected item using the BindingContext
var swipeView = (SwipeView)sender;
var item = (MyClass)swipeView.BindingContext;
where MyClass is the name of the class representing your model

Related

Xamarin.IOS go back from CNContactViewController.FromContact to Application

I have an application written with Xamarin for IOS and Android where I have a list of contacts and when I click on one of them I want to open the according contact in the addressbook of the phone. I have an interface for that implement the method on IOS that way:
private void ShowContactDialog(string addressbookId, bool isEdit = false)
{
var contact = new AddressBookService().GetCnContactById(addressbookId);
var view = CNContactViewController.FromContact(contact);
view.Editing = isEdit;
DisplayView(view);
}
private static void DisplayView(CNContactViewController view)
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
if (vc is UINavigationController navController)
{
vc = navController.ViewControllers.Last();
}
vc.PresentViewController(new UINavigationController(view), true, null);
}
That works so far as it opens the contact:
The issue now is, that there is just an edit button, but now Done, cancel or back button. Therefore I have to kill the whole application and start it again to come back.
Is there a way to add a extra button similar to the edit button to dismiss the dialog again?
EDIT: I adjusted the code as suggested in the comments by Kevin Li.
private void ShowContactDialog(string addressbookId, bool isEdit = false)
{
var contact = new AddressBookService().GetCnContactById(addressbookId);
var view = CNContactViewController.FromContact(contact);
view.Editing = isEdit;
GetCurrentViewController().NavigationController.PushViewController(view, true);
}
private static UIViewController GetCurrentViewController()
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
if (vc is UINavigationController navController)
{
vc = navController.ViewControllers.Last();
}
return vc;
}
Now it is shown within the Tabs:
Unfortunately is the back button not displayed as well.
I tried to make a new UINavigationController, but that didn't change anything.
EDIT2:
I adjusted the way the tabs are created another time. My MainViewController looks like that:
[MvxRootPresentation(WrapInNavigationController = true)]
public class MainViewController : MvxTabBarViewController<MainViewModel>
{
private bool constructed;
private bool firstTimePresented = true;
public MainViewController()
{
constructed = true;
// need this additional call to ViewDidLoad because UIkit creates the view before the C# hierarchy has been constructed
ViewDidLoad();
}
public override async void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (firstTimePresented)
{
// Initialize the tabs
firstTimePresented = false;
await ViewModel.GoToContactListCommand.ExecuteAsync();
await ViewModel.GoToBirthdayListCommand.ExecuteAsync();
await ViewModel.GoToProfileListCommand.ExecuteAsync();
await ViewModel.GoToSettingsCommand.ExecuteAsync();
}
}
public override void ViewDidLoad()
{
if (!constructed)
return;
base.ViewDidLoad();
Title = "Connect Update";
EdgesForExtendedLayout = UIRectEdge.None;
View.BackgroundColor = UIColor.White;
}
}
On each View who shall be a tab has to be this Attribute:
[MvxTabPresentation(TabIconName = "IconCake", TabName = "Birthdays")]
public partial class BirthdayView : MvxViewController<BirthdayViewModel>
The code for opening the contact is the same as above. Now it makes a new View without the tabs but with the back button, exactly as wished :)
The issue now is, that there is just an edit button, but now Done, cancel or back button.
It is because the value of isEdit at view.Editing = isEdit; is false. So, when you present the CNContactViewController, there's only an Edit button. When you click the Edit button, it will change to the editing mode and the Cancel and Done buttons will appear.
Or you can set the value of isEdit to true, then the Cancel and Done buttons will show when the CNContactViewController presents.
Therefore I have to kill the whole application and start it again to come back.
Is there a way to add a extra button similar to the edit button to dismiss the dialog again?
You don't have to kill and restart the app to dismiss the dialog. You can just implement the DidComplete in the delegate: CNContactViewControllerDelegate to dismiss the dialog when user finishes editing the contact and click the Done button or cancel it with clicking the Cancel button.
Here's the related code snippet:
var view = CNContactViewController.FromContact(contact);
view.Delegate = new MyCNConatactViewControllerDelegate();
public class MyCNConatactViewControllerDelegate : CNContactViewControllerDelegate
{
public override void DidComplete(CNContactViewController viewController, Contacts.CNContact contact)
{
viewController.NavigationController.DismissViewController(true, null);
}
}
Update:
To show the Back button in the CNContactViewController:
Make sure the UI hierarchy like this: Navigation->Viewcontroller(Page)->CNContactViewController. Then change the method from Present to Push to show the CNContactViewController, like this:
this.NavigationController.PushViewController(view, true);

How to make my RefreshControl appear during ViewDidAppear

I've answered this question myself - just leaving it here now for people with the same issue.
My code is fairly simple - A custom table with a datasource to provide data asynchronously from a web service.
In order to get the nicest user experience I would like to have the UIRefreshControl animate the process of loading whenever this controller appears, instead of just when the list has been pulled down.
Unfortunately the UIRefreshControl does not appear at all if I call my method during ViewDidAppear.
I've tried suggestions from answers these questions, but none of them seemed to work for me:
public partial class ControlCenterSelectionController : UITableViewController
{
public ControlCenterSelectionController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
TableView.RefreshControl = new UIRefreshControl();
TableView.RefreshControl.ValueChanged += RefreshControlOnValueChanged;
}
private async void RefreshControlOnValueChanged(object sender, EventArgs eventArgs)
{
await UpdateDataSourceAsync();
}
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
TableView.SetContentOffset(new CGPoint(0, -TableView.RefreshControl.Frame.Size.Height), true);
await UpdateDataSourceAsync();
}
private async Task UpdateDataSourceAsync()
{
TableView.RefreshControl.BeginRefreshing();
var ccClient = DI.Instance.Get<IControlCenterRestClient>();
var controlCenters = await ccClient.GetAllAsync();
var source = new GenericViewSource<ControlCenter>(controlCenters, item => item.Name, ControlCenterSelected);
TableView.Source = source;
TableView.RefreshControl.EndRefreshing();
}
private void ControlCenterSelected(ControlCenter controlCenter)
{
var controller = this.InstantiateController(Constants.ViewControllerIds.ControlCenter) as ControlCenterController;
controller.ControlCenter = controlCenter;
this.NavigateTo(controller);
}
}
UITableView UIRefreshControl Does Not Show Its View The First Time
UIRefreshControl on viewDidLoad
UIRefreshControl - beginRefreshing not working when UITableViewController is inside UINavigationController
All I currently get is a screen which looks empty, loads data without indication and then updates the screen once it's done.
Can someone spot an error? I can't really find one, since this code is rather simple.
The desperation of posting it on SO + desperate coding attempts were key:
public override async void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
TableView.SetContentOffset(new CGPoint(0, -(TableView.RefreshControl.Frame.Size.Height + 20)), true);
TableView.RefreshControl.BeginRefreshing();
await UpdateDataSourceAsync();
}
private async Task UpdateDataSourceAsync()
{
var ccClient = DI.Instance.Get<IControlCenterRestClient>();
var controlCenters = await ccClient.GetAllAsync();
var source = new GenericViewSource<ControlCenter>(controlCenters, item => item.Name, ControlCenterSelected);
TableView.Source = source;
TableView.RefreshControl.EndRefreshing();
}
This change in particular made the difference:
-(TableView.RefreshControl.Frame.Size.Height + 20)
Turns out that, while in the other questions the issue was fixed by simply applying a scroll based on RefreshControl would fire the animation, in my case I had to add some extra y delta to make the animation fire.
Correction
this extra offset seems to be required only if extended edges is set to extend under top bars.

UICollectionView Xamarin.iOS, Custom cell with button

I have read many tutorial out there for UICollectionView for both iOS and Xamarin.iOS
Everybody has shown same sample tutorial with one image inside UICollectionViewCell
Desired output
UICollectionViewCell with custom design
What I have done
This is what I have achieved so far.. please ignore the bad design :P
Problem
When I Click on Book button, it triggers the event multiple times. The weird thing is that its not consistent, sometimes it will trigger only once some time twice or some time three times or whatever...
Code Snippet
List<MeetingRoom> data = new List<MeetingRoom>();
async public override void ViewDidLoad()
{
base.ViewDidLoad();
data = await DashboardServices.getMeetingRooms(DateTime.Now);
MeetingRoomCollection.WeakDataSource = this;
}
public nint GetItemsCount(UICollectionView collectionView, nint section)
{
var count = data.Count;
return count;
}
public UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (MeetingRoomCell)collectionView.DequeueReusableCell("cell", indexPath);
cell.RoomName.Text = data[indexPath.Row].Room_Name;
cell.Status.Text = data[indexPath.Row].Availability;
cell.BookButton.Tag = indexPath.Row;
cell.BookButton.TouchUpInside += Cell_BookButton_TouchUpInside;
return cell;
}
void Cell_BookButton_TouchUpInside(object sender, EventArgs e)
{
var x = sender as UIButton;
Debug.WriteLine("index : {0}, status : {1}", (int)x.Tag, data[(int)x.Tag].Availability);
this.PerformSegue("segue_bookRoom", this);
}
Please suggest what needs to be done to fix this issue, any reference to available tutorial would be appreciated. It will be great if Xamarin.iOS hint is there..
One possible way to solve this issue is to unsubscribe from event before subscribing it, this way it will prevent multiple calls especially if this item is recycled in list.
cell.BookButton.TouchUpInside -= Cell_BookButton_TouchUpInside;
cell.BookButton.TouchUpInside += Cell_BookButton_TouchUpInside;

How to open custom dialog box / popup using Xamarin.Forms?

I am newbie to Xamarin.Forms and stuck with a situation where I want to open up a popup box with my control details [e.g. View Employee Details] on click of parent page.
How can I open custom dialog box / popup using Xamarin.Forms?
Any example code will be appreciated?
Thanks in advance!
If you still want to have your popup's code in its own Page you can set up some custom renderers along the following logic.
1. A ModalPage & corresponding renderer
public class ModalPage : ContentPage { }
public class ModalPageRenderer : PageRenderer {
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
this.View.BackgroundColor = UIColor.Clear;
this.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
SetElementSize (new Size (View.Bounds.Width, View.Bounds.Height));
}
}
2. HostPage
public class ModalHostPage : ContentPage, IModalHost
{
#region IModalHost implementation
public Task DisplayPageModal(Page page)
{
var displayEvent = DisplayPageModalRequested;
Task completion = null;
if (displayEvent != null)
{
var eventArgs = new DisplayPageModalRequestedEventArgs(page);
displayEvent(this, eventArgs);
completion = eventArgs.DisplayingPageTask;
}
// If there is no task, just create a new completed one
return completion ?? Task.FromResult<object>(null);
}
#endregion
public event EventHandler<DisplayPageModalRequestedEventArgs> DisplayPageModalRequested;
public sealed class DisplayPageModalRequestedEventArgs : EventArgs
{
public Task DisplayingPageTask { get; set;}
public Page PageToDisplay { get; }
public DisplayPageModalRequestedEventArgs(Page modalPage)
{
PageToDisplay = modalPage;
}
}
}
3. HostPage renderer
public class ModalHostPageRenderer: PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if(e.OldElement as ModalHostPage != null)
{
var hostPage = (ModalHostPage)e.OldElement;
hostPage.DisplayPageModalRequested -= OnDisplayPageModalRequested;
}
if (e.NewElement as ModalHostPage != null)
{
var hostPage = (ModalHostPage)e.NewElement;
hostPage.DisplayPageModalRequested += OnDisplayPageModalRequested;
}
}
void OnDisplayPageModalRequested(object sender, ModalHostPage.DisplayPageModalRequestedEventArgs e)
{
e.PageToDisplay.Parent = this.Element;
var renderer = RendererFactory.GetRenderer (e.PageToDisplay);
e.DisplayingPageTask = this.PresentViewControllerAsync(renderer.ViewController, true);
}
}
Then it is as simple as calling
await ModalHost.DisplayPageModal(new PopUpPage());
from your host page or in this particular case from the ViewModel behind.
What Pete said about PushModalAsync / PopModalAsync still remains valid for this solution too (which in my opinion is not a disadvantage), but your popup would appear with transparent background.
The main advantage of this approach, in my opinion, is that you can have your popup XAML/code definition separate from the host page and reuse it on any other page where you wish to show that popup.
The general purpose of what you are trying to achieve can be accomplished by using the PushModalAsync and PopModalAsync methods of Xamarin.Forms Navigation object.
The chances are that this is good enough for what you are needing - However - this isn't truely modal. I will explain after a small code snippet:-
StackLayout objStackLayout = new StackLayout()
{
};
//
Button cmdButton_LaunchModalPage = new Button();
cmdButton_LaunchModalPage.Text = "Launch Modal Window";
objStackLayout.Children.Add(cmdButton_LaunchModalPage);
//
cmdButton_LaunchModalPage.Clicked += (async (o2, e2) =>
{
ContentPage objModalPage = new ContentPage();
objModalPage.Content = await CreatePageContent_Page2();
//
await Navigation.PushModalAsync(objModalPage);
//
// Code will get executed immediately here before the page is dismissed above.
});
//
return objStackLayout;
private async Task<StackLayout> CreatePageContent_Page2()
{
StackLayout objStackLayout = new StackLayout()
{
};
//
Button cmdButton_CloseModalPage = new Button();
cmdButton_CloseModalPage.Text = "Close";
objStackLayout.Children.Add(cmdButton_CloseModalPage);
//
cmdButton_CloseModalPage.Clicked += ((o2, e2) =>
{
this.Navigation.PopModalAsync();
});
//
return objStackLayout;
}
The problem with the above is that the
await Navigation.PushModalAsync(objModalPage);
will immediately return after the animation.
Although you can't interact with the previous page, as we are displaying a new NavigationPage with a Close button shown - the parent Navigation Page is still executing behind the scenes in parallel.
So if you had any timers or anything executing these still would get called unless you stopped those.
You could also use the TaskCompletionSource approach as outlined in the following post also How can I await modal form dismissal using Xamarin.Forms?.
Note - that although you can now await the 2nd page displaying and then when that page is dismissed allowing code execution to continue on the next line - this is still not truely a modal form. Again timers or anything executing still will get called on the parent page.
Update 1:-
To have the content appear over the top of existing content then simply include it on the current page, however make this section of content invisible until you need it.
If you use an outer container such like a Grid that supports multiple child controls in the same cell, then you will be able to achieve what you want.
You will also want to use something like a filled Box with transparency that will cover the entire page also, to control the visible, see through section, that surrounds your inner content section.
I followed above approach and found it impossible to run on iOS 7.
I found this library BTProgressHUD which you can modify and use.
I Use its methods by Dependency service.
Actual library for popups.
https://github.com/nicwise/BTProgressHUD
Following example uses BTProgressHUD library internally.
https://github.com/xximjasonxx/ScorePredictForms

Nested Silverlight Datagrid - Row Details works great, but I want a button!

I'm using a silverlight 3 datagrid, and within it, I'm nesting related records in another control by using the rowdetails (visibilitymode = visiblewhenselected).
I really like how this works, but I'd much rather have the grid display the row details when a "+" button is pressed, much as a tree will expand when you click a node.
I tried programmatically defining the template by using resources like this:
<Grid.Resources>
<DataTemplate x:Key="EmptyTemplate">
<StackPanel>
<!--<TextBlock Text="Empty Template!!!" />-->
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="SongTemplate">
<StackPanel>
<AdminControls:ArtistSongControl x:Name="ArtistSongControl" />
</Stack>
</DataTemplate>
</Grid.Resources>
And in the grid's LoadingRowDetails event, I'd choose which template to set by:
e.Row.DetailsTemplate = (DataTemplate)LayoutRoot.Resources["SongTemplate"];
This sortof worked, but I found that I had problems with collapsing previous rows details template, and even crashed ie8 (not sure if that's related).
Basically, I really like how the silverlight 3 datagrid works, and even how the rowdetailstemplate stuff is implemented. I simply would like to defer loading any details until a row is expanded purposely (as a tree would be). All of the 3rd party grids seem to do this, and microsoft's is soooo close. Does anyone have any idea how to solve this one?
Thanks, Dennis
Dennis,
In case you haven't already found an answer to this, I wanted the same behavior and solved it by customizing the RowHeaderTemplate, which lets you throw a button in the header for each row. Then I implemented a handler for the button like so:
private void ToggleButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
ToggleButton button = sender as ToggleButton;
DataGridRow row = button.GetVisualAncestorOfType<DataGridRow>();
if (button.IsChecked == true)
{
row.DetailsVisibility = Visibility.Visible;
//Hide any already expanded row. We only want one expanded at a time for simplicity and
//because it masks a virtualization bug in the datagrid.
if (_expandedRow != null)
_expandedRow.DetailsVisibility = Visibility.Collapsed;
_expandedRow = row;
}
else
{
row.DetailsVisibility = Visibility.Collapsed;
_expandedRow = null;
}
}
Note that GetVisualAncestorOfType<> is an extension method I've implemented to dig into the visual tree.
You'll also need to set the datagrid's HeadersVisibility property to Row or All
here is another way to achieve what you are trying to do:
In the DataGrid set up a LoadingRow Event like this:
<data:DataGrid LoadingRow="ItemsGrid_LoadingRow" .....
In the DataGrid create a Template Column which will contain a Button such as the following:
<data:DataGridTemplateColumn CellStyle="{StaticResource DataGridCellStyle1}" CanUserReorder="False">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="ViewButton" Click="ToggleRowDetailsVisibility" Cursor="Hand" Content="View Details" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
In the LoadingRow Event locate the button that is (in this case) stored in the first column of the DataGrid, then store the current DataGridRow into the buttons Tag element
private void ItemsGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
var ViewButton = (Button)ItemsGrid.Columns[0].GetCellContent(e.Row).FindName("ViewButton");
ViewButton.Tag = e.Row;
}
In the Buttons EventHandler (in this case ToggleRowDetailsVisibility) we will extract the Row so that we can toggle its DetailsVisibility
In the LoadingRow Event locate the button that is (in this case) stored in the first column of the DataGrid, then store the current DataGridRow into the buttons Tag element
private void ToggleRowDetailsVisibility(object sender, RoutedEventArgs e)
{
var Button = sender as Button;
var Row = Button.Tag as DataGridRow;
if(Row != null)
{
if(Row.DetailsVisibility == Visibility.Collapsed)
{
Row.DetailsVisibility = Visibility.Visible;
//Hide any already expanded row. We only want one expanded at a time for simplicity and
//because it masks a virtualization bug in the datagrid.
if (CurrentlyExpandedRow != null)
{
CurrentlyExpandedRow.DetailsVisibility = Visibility.Collapsed;
}
CurrentlyExpandedRow = Row;
}
else
{
Row.DetailsVisibility = Visibility.Collapsed;
CurrentlyExpandedRow = null;
}
}
}
You will notice that "CurrentlyExpandedRow", this is a Global variable, of type DataGridRow, that we store the currently expanded row in, this allows us to close that Row when a new one is to be opened.
Hope this helps.
In addition to the answer uxrx provided here is the code for finding an ancestor
public static partial class Extensions
{
public static T FindAncestor<T>(DependencyObject obj) where T : DependencyObject
{
while (obj != null)
{
T o = obj as T;
if (o != null)
return o;
obj = VisualTreeHelper.GetParent(obj);
}
return null;
}
public static T FindAncestor<T>(this UIElement obj) where T : UIElement
{
return FindAncestor<T>((DependencyObject)obj);
}
}
For this:
DataGridRow row = button.GetVisualAncestorOfType<DataGridRow>();
We can use as:
HyperlinkButton button = sender as HyperlinkButton;
DataGridRow Row = DataGridRow.GetRowContainingElement(button)
I suggest you take a look at the RowVisibilityChanged event on the datagrid, basically when the row visibility changes to "Visible", then load the info for the row.

Resources