ProgressHUD and TouchUpInside - c#

I have my ViewController like
public partial class TestView
: MvxViewController
{
...code here...
}
and i load my next ViewController on button event TouchUpInside like that:
btnSearch.TouchUpInside += (object sender, EventArgs e) => {
BTProgressHUD.Show("test");
ViewModel.GoParameterizedCommand.Execute(null);
};
that event it's defined in ViewDidLoad. My "test" message it's showed on next ViewController and not during loading of this one. How could i show that message during loading and not when next ViewController is loaded? I have tried to use also MBProgressHUD
btnSearch.TouchUpInside += (object sender, EventArgs e) => {
var hud = new MTMBProgressHUD (View) {
LabelText = "Waiting...",
RemoveFromSuperViewOnHide = true
};
View.AddSubview(hud);
hud.Show (animated: true);
ViewModel.GoParameterizedCommand.Execute(null);
};
but behaviour it's same.

It seems that you are trying to work with ProgressHUD in View layer. In MVVM-way you should create a "Loading" property in your ViewModel and bind it to progressbar in View.
Here is a good Stuart's video how to do that: http://youtu.be/6fNXGErr9to
And here is sample code: https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress

I am doing something similar in one of my apps.
I have a IsLoading property in my ViewModel which I set whether something is loading and not. Then in my ViewController I am subscribing to changes on Loading like this:
ViewModel.WeakSubscribe(() => ViewModel.IsLoading, (sender, args) =>
{
if (ViewModel.IsLoading)
{
ShowLoadingDialog("Loading Resource");
}
else
{
DismissLoadingDialog();
}
});
void ShowLoadingDialog(string text)
{
DismissLoadingDialog();
BTProgressHUD.Show(text, -1, BTProgressHUD.MaskType.Black);
}
void DismissLoadingDialog()
{
if (BTProgressHUD.IsVisible)
BTProgressHUD.Dismiss();
}
I do this in ViewDidLoad(). You could do something similar in your first View, then in your second you could just call DismissLoadingDialog() or simply make sure you call ViewWillDisappear() or ViewDidDisappear(), in the first ViewModel, so it gets dismissed correctly.

Loading view controller will not take more then 'Micro Seconds'.
Loading data in the view controller will need some time and during that time you need to show that ProgressHUD.
If you are loading data in 'First View Controller' then at start loading data start ProgressHud with BTProgressHUD.Show("test"); and when your data is done loading remove that HUD from the view just before navigating to the 'Second View controller'.
And if, you are loading data in 'Second View Controller', then Do navigation first from 'First View Controller' to 'Second View Controller' and then show HUD just before loading data in Second view controller BTProgressHUD.Show("test"); and remove it after data is loaded.

Related

C# WPF Affecting main thread from UserControl class

I am trying to make a simple image viewer that loads images at start, creates Items with pulled SQL data and then creates Dictionary with all the Item parameters.
Then another method builds what's needed and fills StackPanel with UserControls (ITEM) that act as "links" to images.
Trying to add another image, from UserControl (NEW_ITEM) nested in View that is loaded to ContentControl in MainWindow.
public partial class fileUpload : UserControl
{
public fileUpload()
{
InitializeComponent();
}
string PathSource = #"SOURCE";
string PathToCopy = #"DESTINATION";
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
PathSource = FU_source.Text;
if (!FU_fileName.Text.Contains("."))
{
MainWindow V = new MainWindow();
V.LoadCollection(); //This seems to work, but the content on MainWindow stays visible.
////Copy Inserted Item
File.Copy(PathSource,PathToCopy + FU_fileName.Text + ".png", true);
////Remove Item Preview From List
((ItemsControl)this.Parent).Items.Remove(this);
}
else
{
MessageBox.Show("ERR TEST", "ERR TEST HEADER");
}
}
}
Running LoadCollection() method does work OK if it's called from the MainWindow but does not work if called from fileUpload Class. (Program seems to do what's needed, but the user control won't disappear.)
Basically, it should refresh the whole process and refresh/refill StackPanel with new items.
I have encountered this problem many times and I think that I'm missing a key part in this.
TL;DR: I am trying to refresh MainWindows StackPanel with new Items, but the controls won't disappear if method taking care of this is called from UC Class.

Perform a segue from a UITableView to a new view controller Xamarin

I have a Xamarin.iOS application which includes a Navigation Controller where the root in a View Controller ViewController.cs, inside the UIViewController (the default one created in a single view application) is a Table View which has a segue to a new View Controller.
Depicted in Storyboard below.
The Table view is controlled by the StationsTableViewSource.cs code which inherits from UITableViewSource. The source for the Table View is set inside the ViewController.cs.
StationsTable.Source = new StationsTableViewSource(StationPlayer.StationsTitleList)
When I press a cell in the table view I want to segue to the new view controller but as I see it:
I have no access to the Parent/Root/Containing View Controller from the Table View
I have no access to the New View Controller from the Table View.
My question is this, with a set up as above, how can I perform a segue from a cell inside a tableview nested in a View Controller to another View Controller?
Please correct the terminology - not too hot on Xamarin/iOS lingo.
Thanks all.
First of all, we need to figure out which segue have you created?
1.From your tableViewCell to a new ViewController.
This means: tap down on the Cell + ctrl and drag to a new ViewContoller. In this way, there's no need to execute PerformSegue() manually. When you click the Cell, it will push to a new Controller.
2.From your ViewContoller to a new ViewController
This means: tap down on the bottom bar of the ViewContoller + ctrl and drag to a new ViewController. In this way, we need to click the segue we created above then set the Identifier. When we click the Cell, the event below will be triggered:
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
//use this method we can push to a new viewController
//the first parameter is the identifier we set above
parentVC.PerformSegue("NewPush", indexPath);
}
I have no access to the Parent/Root/Containing View Controller from
the Table View
When you construct this Source you can pass your "Parent" ViewController like:
ViewController parentVC;
//You can add other parameters you want in this initial method
public MyTableViewCellSource(ViewController viewController, ...)
{
parentVC = viewController;
}
Moreover both segues will fire PrepareForSegue() in the parent ViewController. In this method you can pass parameters to the new ViewController:
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
if (segue.Identifier == "NewPush")
{
SecondVC secondVC = segue.DestinationViewController as SecondVC;
...//do some configuration
}
}
About how to use segue, you can read this official documentation for more details.

How to go back to previous ViewController in Xamarin.IOS

I make an app in VisualStudio Xamarin (not Xamarin.Forms) with two view controller. First view controller is list of items, second contain item's detail info. When user tap item in list, second view opens with code
DetailViewController detailController = this.Storyboard.InstantiateViewController("DetailViewController") as DetailViewController;
detailController._idx = idx;
this.NavigationController.PushViewController(detailController, true);
But I don't know how to go back to first ViewController programmatically - for example there are button "Go Back" on DetailViewController
I try to use this code:
backButton.TouchUpInside += (s,e) => {
this.NavigationController.DismissViewController(true, null)
};
But it doesn't give any result.
Can anybody help me with this?
UPDATED
I changed code to:
backButton.TouchUpInside += (s,e) => {
this.NavigationController.DismissViewController(true, async () => { await DismissViewControllerAsync(true); });
ListViewController listController = this.Storyboard.InstantiateViewController("ListViewController ") as ListViewController;
this.NavigationController.PresentViewController(listController, true, null);
}
This work for "Go back", but when I try to choose same or another item in list and open new DetailViewController, it throw exception "System.NullReferenceException: Object reference not set to an instance of an object" on
this.NavigationController.PushViewController(detailController, true);
(In details - I run app, ListViewController opens, I choose item1, DetailViewController opens, I tap BackButton, ListViewController opens, I chhose any item, Exception)
You got Push,Pop and Present,Dismiss mixed up.
When the viewcontroller is put inside Navigation, you should use push and pop to control the stack.
Modify your code :
backButton.TouchUpInside += (s,e) => {
this.NavigationController.PopViewController(true);
}
Refer to
Presenting a View Controller
UINavigationController
If you need a "back" butten to apear automatically then you need to start with a navigation controller, and from there open a viewcontroller...
See more at this link:
https://developer.xamarin.com/guides/ios/getting_started/hello,_iOS_multiscreen/hello,_iOS_multiscreen_quickstart/
otherwise you need to make a butten and simply just use the samee method as before!
Ask if you don't understand it!

Caliburn Micro Screen Activated Events

I'm using Caliburn Micro and AvalonDock in my project. I try to handle events when screen was activated. My main view model is a 'Conductor.Collection.OneActive' and each tab "document" is a 'Screen'.
I have a function in my main view model like this:
public void CheckAndRegisterDocument(DocumentViewModel document)
{
DocumentViewModel exists = _documents.FirstOrDefault((d) => { return d.Equals(document); });
// if not exists - add it
if(exists == null) {
document.Activated += Document_Activated;
_documents.Add(document);
Items.Add(document);
}
// activate and set property object
ActivateItem(document);
Properties.PropertiesObject = document.Properties;
}
// document activated event handler
private void Document_Activated(object sender, ActivationEventArgs e) {
ActiveDocument = sender as DocumentViewModel;
}
But the function "Document_Activated" is not invoked. what am I doing wrong?
Instead of adding your document objects into a documents collection, add them to the already existing this.Items collection.
Also, each document object will need to inherit from Screen for it to participate.
That +should+ be enough to do the trick, but sometimes it can be necessary to tell Caliburn to "conduct" your viewmodels via ConductWith...
document.ConductWith(this)
there this is the current conductor viewmodel.

LongListSelector doesn't refresh correctly when only 1 object is in collection

I have a problem with caliburn micro and Longlistselector.
BindableCollection from my viewmodel is bind to ItemSource in LLS in view.
In OnActivate method I load data from local database to my BindableCollection to refresh LLS. From my list page I can go to another page to edit selected item on list, and after save I return back to my list page.
Then again OnActivate method is invoked which fetch all objects of SomeType from local database and assign new BindableCollection so LLS is updated.
This works great when more than 1 element is in local database. But when there is only one object on local database, the LLS is not updated after edit, still presents the same data before edit.
What is more, when I go again to edit this object to edit page, the correct data are displayed.
Below are my OnActivate method
protected override void OnActivate()
{
base.OnActivate();
Task<List<Person>>.Factory.StartNew(() => _service.GetPresons()).ContinueWith(
x => Execute.BeginOnUIThread(() =>
{
this.Persons = new BindableCollection<Person>(x.Result);
}));
}
Any ideas how to fix that ?
Try not recreating the collection on every page activation.
Put this collection init to your constructor
Persons = new BindableCollection<Person>()
and in change the OnActivate method to
protected override void OnActivate()
{
base.OnActivate();
var res = _service.GetPresons();
Persons.Clear();
Persons.AddRange(res);
}

Categories

Resources