I have a simple WebView application. In one of the cases, I show a file, to allow user go back a UINavigationBar is shown:
navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 20, 320, 44)];
navigationItem = [[UINavigationItem alloc] init];
navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(buttonClicked:)];;
[navigationBar pushNavigationItem:navigationItem animated:YES];
[self.view addSubview:navigationBar];
This is working nice. It shows a back button, and when back button is clicked it executes selector (button style must be improved, but I'm newbie with xCode and c# and this will come later).
In the selector i load previous url, but I can't figure out how to hide button and bar.
- (IBAction) buttonClicked:(id)sender {
return [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString: lastURL]]];
}
I've tried several things, like removeFromSuperView:
[navigationBar removeFromSuperview];
Hide it:
[self.navigationController setNavigationBarHidden:YES animated:YES];
self.navigationController.navigationBar.hidden = YES;
// or
[navigationItem hidesBackButton];
// or
navigationBar.hidden = TRUE;
Using the selector (id):
[sender show:NO];
Using the alpha property:
navigationBar.alpha = 0,0;
Free memory space:
navigationItem.dealloc;
But nothing works... I think I'm missing some important detail, because I don't know really how xCode works...
Any help will be appreciated!
Personally, I would never add a navigation bar like that, but rather have a root navigation controller, which has a root view controller that holds a webview as it's view.
You did not make it very clear, how do you actually show the file?
Anyway, this code:
[self.navigationController setNavigationBarHidden:YES animated:YES];
is not working for you because you haven't provided your view controller with a navigation controller.
Provide one, maybe best in the main storyboard, and setup your view controller (that holds the webview) as its root view controller. To do that, open the storyboard, and drag/drop a UINavigationController to the main area. You have to tick the option "Is Initial View Controller". Note: when you did the drag/drop, a default root view controller was already provided. You can either leave that one, or provide your own, if you already had one in the storyboard. To do that, delete the linked one, and ctrl-click and drag from the Navigation Controller to the View Controller, to setup it as its Root View Controller. I've attached an image to showcase what I've described.
Related
I have a Windows Phone 8.1 app using Caliburn.Micro. In the app I have a few ViewModels that fetch data in different way and with different logic but show them in the same way. So I want to make all those ViewModel use the same one View.
I found out that ViewLocator.LocateTypeForModelType is a method that gets executed for mapping ViewModels to Views. So I override it to use my custom attribute when present:
var original = ViewLocator.LocateTypeForModelType;
ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =>
{
var useViewAttributes = modelType.GetTypeInfo().GetCustomAttributes<UseViewAttribute>(true);
if (useViewAttributes.Count() == 1)
{
var viewTypeName = string.Concat(modelType.Namespace.Replace("Model", string.Empty), ".", useViewAttributes.First().ViewName);
var type = AssemblySource.FindTypeByNames(new List<string>() { viewTypeName });
return type;
}
return original(modelType, displayLocation, context);
};
Stepping through the it seems to work fine. If I navigate to a ViewModel and that ViewModel has a UseView, my method returs the correct View.
The app navigates to the correct View but the ViewModel is never created. Kind of like Caliburn.Micro forgot about the ViewModel, or was looking for one using a different convention, or something.
I found out that ViewModelLocator.LocateTypeForViewType is called after navigation to a View to resolve the ViewModel. The ViewModel type from the previous step seems to be forgotten completely.
In ViewModelLocator.LocateTypeForViewType I only have access to the View type and I do not know, how to make it resolve the correct ViewModel from the previous step. I could scan all the ViewModel and find the ones with the correct attribute, but I would not know which one to choose.
Any ideas on how to approach this?
Here is a minimal project showing my setup: https://dl.dropboxusercontent.com/u/73642/CMVMTest.zip
This sort of solution would work everywhere else except for the top level navigation. The reason for this is there is sort of a "double dispatch: going on when you navigate.
As you know the Frame or PhoneNavigationFrame control (depending on WinRT or Silverlight) is view based in it's navigation. So the steps look a little like this.
Your code tells the navigation servie=ce to navigate to ProductViewModel.
It uses ViewLocator (where you've injected your code) to locate ProductView and tells the Frame to navigate to that.
The navigation service then responds to the navigating event to ProductView and locates the correct view model using ViewModelLocator.
It then instantiates and binds this view model.
This sort of view model to view to view model step in navigation service causes the hiccup in your code.
You should be able to create dummy views that simply inherit the base view and add nothing. So if you have MySharedView.xaml then declaring what's below should be enough.
public class SecondView : MySharedView { }
It's not ideal I know, but does get you the reuse you're after. Having the navigation service remember the view model between the navigating and navigated events becomes complicated with all the external factors that can cause navigation as well.
In My app, i use an altered Example of the ViewPagerIndicator, which launches 5 Fragments. so far all works well, but the fragments do have to change their View (completly new layout) for other purposes. how do i do that? a Fragment doesn't have a function SetContentView like activities do. so is there a way to update the view or something like that?
Use Fragment.getView() to get the root view of the Fragment. On that View, call removeAllViews(). Then build your new views and add them to the view you got from getView().
Edit
I never used Mono for Android before, but looking at the documentation; I suggest you put the inflated View from inflater.Inflate in a private member of your Fragment. Later on, when needed, you can use that reference to edit your layout.
please forgive the newness level I'll be exhibiting.
I created a new iPad Master/Detail (UISplitViewController) app in Monotouch.
The master controller on the left is a UITableViewController. The detail on the right is just a UIViewConroller. These are loaded by default in the AppDelegate code.
In the master controller I then added some items to the table and overrode the RowSelected() event and that works great, so I can get the item selected. I've added an additional UIViewController (DetailViewController2) that I want to display on the right side of the screen when an item is selected in the table. It really doesn't matter which item, I just want to change the contents of the right side where the DetailViewController is to the DetailViewController2. I've tried a lot of things and nothing working -- I know this should be obvious, but I'm lost.
Thanks for any help.
If you are using UISplitViewController, the way to change the master and detail controller is to update the ViewControllers property. It always wants both, the master and the detail controller.
If you want to update the detail only, your code would be something like this:
var masterController = splitController.ViewControllers[0];
var newDetailController = new DetailViewController2();
splitController.ViewControllers = new UIViewController[] { masterController, newDetailController };
For Documentation see here:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
MonoTouch is 5.2.12. iOS is v5.1.1 (Simulator)
Seems like I'm missing an important piece of a puzzle here.
I'm subclassing DialogViewController and set it as the only controller in my UINavigationController.
In ViewWillAppear of the subclassed DialogViewController, I'm trying to set the left and right bar button items:
this.NavigationController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Done, this.HandleDoneButtonTouched );
Neither one of them is showing up. The title however is displayed. If I debug, I can see that the items are properly set.
I have also tried to use SetItems() on the navigation controller: no effects either.
The navigation controller is presented modally in a page sheet.
Navigation items are not usually updated through the navigation controller. Instead, they are updated via the NavigationItem property on the view controller:
this.NavigationItem.SetRightBarButtonItem(
new UIBarButtonItem(UIImage.FromFile("some_image.png")
, UIBarButtonItemStyle.Plain
, (sender,args) => {
// button was clicked
})
, true);
http://docs.xamarin.com/ios/recipes/Content_Controls/Navigation_Controller/Add_a_Nav_Bar_Right_Button
I'm working on a sort of a CMS/Wiki application to help me experiment with the new Asp.Net MVC framework, and I'm trying to wrap my head around some of the code organization.
Right now, I have three views that cover displaying an article: Index, Edit, and Rename. All three views display the contents of the current page, or placeholder content stating that the page does not exist.
This is currently accomplished with the following code in the action method for each view:
MyPage myPage = null;
if (!string.IsNullOrEmpty(pageName)) {
myPage = mRepository.GetMyPage(pageName);
}
//Page does not exist.
if (myPage != null) {
ViewData["pageContent"] = myPage.GetParsedSource(new PageState());
ViewData["pageSource"] = myPage.Source;
ViewData["title"] = myPage.Title;
}
else {
ViewData["title"] = pageName;
ViewData["pageContent"] = "Page does not exist, feel free to create it!";
ViewData["pageSource"] = "";
}
ViewData["pageName"] = pageName;
My question is, where should this logic actually go?
1) The Controller (as it is now), which requires the above code to be replicated across action methods?
2) The Model, defaulting values for pageSource to the verbiage shown above? This would have the downside of moving display text into the model.
3) The View, using a null coalescing operator to convert null ViewData entries to their defaults?
4) In the Views, but add additional controllers to handle cases where the pageName does not exist.
EDIT:
Hopefully this should clarify things a little. The flow of the application is as follows:
When the user enters a URL (i.e. /pages/page_title), they arrive at a screen which displays the content of the article, along with hyperlinks labeled "edit" and "rename."
Clicking edit displays a page which contains the article content, as well as form controls to edit the article's source.
Clicking rename displays a page which contains the article content, as well as form controls to edit the article's name.
I would have several actions:
Lookup
Display
Create
Edit
Rename
In your default Lookup controller action (which gets hit when the user asks for, say, "/wiki/article-title"), you can redirect (RedirectToAction()) to the appropriate action as necessary. That encapsulates your Create logic into its own controller, and can also be called directly (RESTful). Same with the others. That also allows you to keep your views very, very stupid (always a good thing).
I would keep it in the controller but extract it out so that you don't have to replicate the code in each of the actions.
Maybe set some defaults in the controller's constructor and then have a separate private method (ie. not an action method) that takes your MyPage object and sets the viewdata that is shared between your actions.