I have a collectionview, and when you click on the collectionview item it opens up my mopup popup displaying that data. That works fine. When I click my delete button on the popup to delete that collectionview item my handler deletes and dismisses the popup but I need to figure out how to call OnAppearing on the initial class with the collectionview so that the source for the collectionview gets updated.
I know there is the BackgroundClicked event handler but that is not able to call OnAppearing in another class.
I am currently not using MVVM and not very good at it. Hoping there is an easy way to achieve this.
Edit:
private async void DeleteItem_Clicked(object sender, EventArgs e)
{
var result = await DisplayAlert("Delete", $"Delete {Item.Name} from the database", "Yes", "No");
if (result)
{
await App.Database.DeleteItem(item);
await MopupService.Instance.PopAsync();
}
}
Item is the object passed in to the popup that I want to delete via popup menu then update my collectionview on the base class where the popup was launched from initially.
I used the messagingcenter to subscribe to my popup page from my mainpage, then sent the item back I wanted to delete in my ObservableCollection through messagingcenter.send.
Related
Project and problem explanation
In my case I have a page which instructs the user how to move a certain machine. This page is supposed to be a modal page since the page should not be navigated away from without performing or completely canceling the action.
I have a mainpage with a listview which opens the details page of any of the items contained in the listview on click through the onSelect method:
Navigation.PushAsync(new FooPage(string Name)); /* gets called in the
onSelect method if selection is not null*/
The model is retrieved within the details page's viewmodel after passing the name to it and then using a model manager injected into the viewmodel with Unity to retrieve it.
-- we now both have a mainpage and detailspage on the stack which of only the detailspage has a backbutton --
On the detailspage we have a button called "Teach" with a x,y,z field next to it after clicking it this method gets called:
private async Task Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new ManualTeachPage());
}
which then, as it should, creates the page but then for some reason decides to add a back button to it:
Debugging and Research
This behavior is not visible on Android which does not have a visible back button or navigation bar on this page but does have a backbutton on the Details-page as well.
I have used modal pages before but I have never seen this kind of behavior, I have tried using the Navigation property of the Application.Mainpage itself which resulted in the exact same result except for one case.
I thought it might have something to do with me switching out the Application.Mainpage at one point(there is a stack of tutorial pages the user has to go through), seems like calling the pushModalAsync one line AFTER setting the new mainpage then it DOES push the page as a modal page and performs like one (without a back button) but does not do so after this point.
No bug reports on Bugzilla about this either as far as I have seen, neither have I found anything on the internet about this particular problem.
Note that when clicking the back button on the teachPage it returns to the detailspage. When the teachPage gets pushed it does actually get pushed onto the ModalStack.
update 1
Checked again if the modal page which I was talking about was the only modal page on the modal Stack, it was. NavigationPage.SetHasBackButton(this, false); does not seem to work either as suggested by Diego Rafael Souza.
update 2
I thought I would temporarily disable the backbutton by using the onBackButtonPressed within the teachpage until I had found a solution. Turns out this doesn't work for UWP anymore, this method does not get called anymore on this page or any page for that matter. It does work for the Android Hardware button though.
update 3
I tried using:
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Collapsed;
This does hide the backbutton on UWP but for some reason #if WINDOWS_UWP doesn't work at all. If I do this without the #if the program won't build for Android. No solution yet, not only this but when using this fix the other pages still had the onBackButtonPressed method disabled.
update 4
after updating to the newest version of xamarin forms the OnBackButtonPressed started working again. The backbutton still appears on the page but I now have disabled it.
Recreating the problem
I recreated the problem in this small test project:
https://www.dropbox.com/sh/6btsud3uvw503ee/AAAiaGb3TwhMrZMJb2j-rd36a?dl=0
In your function Button_Clicked() in your example, in page DetailPage, where you call your Modal, right after calling PushModalAsync(new TeachPage());, use:
NavigationPage.SetHasNavigationBar(this, false);
NavigationPage.SetHasBackButton(this, false);
My guess is when you tried using the above SetHasBackButton, you were doing it on the Modal itself, but the back button you were actually seeing came from your DetailPage.
Once you add this, the modal pops up, and the back button disappears. If you set a "Back" button on your modal in order to close it, you can easily get your NavBar and BackButton back in your DetailPage by adding in an OnAppearing() Function in your DetailPage code-behind like so:
protected override void OnAppearing()
{
base.OnAppearing(); // do the usual stuff OnAppearing does
NavigationPage.SetHasNavigationBar(this, true); //get your navbar back
NavigationPage.SetHasBackButton(this, true); //get your back button back
}
I'm navigating to a view when its module gets loaded:
public void OnImportsSatisfied()
{
this.ModuleManager.LoadModuleCompleted +=
(s, e) =>
{
if (e.ModuleInfo.ModuleName == EmailModuleName)
{
this.RegionManager.RequestNavigate(
RegionNames.MainContentRegion,
InboxViewUri);
}
};
}
when I navigate to this view I want to raise a NotificationRequest (and his PopupWindow); this method is defined in the ViewModel:
void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
{
MyInteractionRequest.Raise(...);
}
Through debugging I discovered that the InteractionRequest has no subscribers to its Raised event for the first time I navigate to the view, and that's why no interaction window is shown. In order to make the InteractionRequest work I need to navigate to another view and then go back.
Why does this happend? Does the view get created too late after the viewmodel and so it cant subscribe the InteractionTrigger to the Interaction Request?
My guess is that the view has not been initialized by the time you raise the request. This means no bindings have been created and no handlers have been added. You approach in general is bad practice. If you must show a popup when the page is first show, add an event to command behavior for the view's loaded event and show your popup there. This ensures that the pages has been fully loaded and all bindings have been made.
I'm developing some app for Windows phone 8.1, and I have this problem:
Have 1 form with some checkbox, radio buttons and some text fields. When I fill it up, and move to next form with:
Frame.Navigate(typeof(SOME_FORM));
and I have some things to do, and want to come back to 1st form, it's all cleared. How to remember what i fill up on 1st form, when i come back from 2nd?
And I add all controls programmatically, so I can't save it in static variable.
Any help?
In your first page set property NavigationCacheMode to Required
in XAML
NavigationCacheMode="Required"
or in code behind
this.NavigationCacheMode = NavigationCacheMode.Required;
But the question is: when do you add controls to page? if you add control in OnNavigatedTo you should check NavigationMode and don't reload page on back navigation
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
//do nothing - filled controls already there
return;
}
//add controls
}
I have a WPF application where i use Frame to load Page'is. On the Page i call my custom contol <Controls:OrderDataGrid x:Name="cntrlOrderDataGrid" />.
On this control i have DataGrid what is filled with data when i navigate to the Page inside the Frame. Sometimes the loading takes a while and i need to know when the DataGrid finishes loading, so i have set the Loaded event:
private void dgOrders_Loaded(object sender, RoutedEventArgs e)
{ }
But i cant figure out could i notify the MainWindow that the DataGrid has ended loading. When i set the Loaded event to the Frame then its fired right away without waiting for my custom control with datagrid.
You need to effectively pass the event up.
The Page that holds the datagrid needs to add a new event; something like OrdersLoaded. When the datagrid finishes loading fire that event. The main window can then subscribe to that event, thus telling it when the orders are loaded.
public event Action OrdersLoaded;
private void dgOrders_Loaded(object sender, RoutedEventArgs e)
{
if (OrdersLoaded != null)
OrdersLoaded();
}
I'm creating a basic database application in WPF, and I have started using the MVVM pattern.
I have a dialog that asks the user to select an item from a ListBox and click "OK." After that, I take the item the user clicked from a property in the view model and pass it into another dialog. But if the user clicks "Cancel," I set that value to null, and the action is canceled: I don't open the next dialog and return to the main screen. Example:
public class SelectEquipmentViewModel : WorkspaceViewModel
{
private bool _selected;
public Equipment SelectedEquipment
{
// Item selected by the user
}
// Action for "SelectCommand," which is attached to
// the "Select" button in the view
public void ExecuteSelect()
{
_selected = true;
// Fires a RequestClose event in WorkspaceViewModel,
// which is attached to the view's Close method
RequestClose();
}
public override void RequestClose()
{
if (!_selected)
{
// The user clicked "Cancel"
SelectedEquipment = null;
}
base.RequestClose();
}
}
This has been working great, but the problem comes if the user clicks the red "X" close button in the window's control box. The RequestClose method never gets invoked, and the selected item isn't set to null, which is bad.
I've considered attaching the view model to the Closing event of the view, but I feel this could get messy if I start creating handlers for all these events.
What would be the "preferred" way of handling this situation?
Thanks.
I think that using the EventToCommand behavior to wire up the Window object's Closing event to a new ExecuteCancel command is pretty clean.
public void ExecuteCancel()
{
_selected = false;
// Fires a RequestClose event in WorkspaceViewModel,
// which is attached to the view's Close method
RequestClose();
}
Where do you think this will get messy? If you add a Cancel button, it could use the same ExecuteCancel bits...
Behaviors are what you want to use to execute a command when the user presses the "X" button on window using MVVM. Check out Reed Copsey's blog here: http://reedcopsey.com/2009/10/09/using-behaviors-to-allow-the-viewmodel-to-manage-view-lifetime-in-m-v-vm/
You can download a sample application here...
I use this method all the time to allow the ViewModel manage the life of the view.
Approach without additional dependencies is described in article Handling a Window's Closed and Closing events in the View-Model and code with example provided. This does not add code behind xaml.
(Thanks to Reed Copsey's link)