Failed to create view from XIB UI using Xamarin and MvvmCross - xamarin.ios

I'm have a Xamarin.iOS app. It was written some time ago and used XIB to define user interface. I want to add new view (and controller for it) but every time I'm adding new page and launching the app I get the following error:
Failed to marshal the Objective-C object 0x17a37a70 (type: LoginView). Could not find an existing managed instance for this object, nor was it possible to create a new managed instance (because the type 'Touch.LoginView' does not have a constructor that takes one IntPtr argument).
Additional information:
Selector: viewDidLoad
Method: Touch.LoginView:ViewDidLoad ()
What is more interesting if I'm creating new view by copying existing one and renaming it - everything works fine. I tried to figure out what is the difference but the only thing I found is the following:
If you noticed the extra level of hierarchy was added.
What it is the level and why my app continue to fail with newly created view (i have to copy existing one if I want new view).

This kind of error message can be a real pain normally. In your case, you're pretty lucky as there is a very simple fix to this. When working with xib or storyboard files, you want to have the following in your controllers:
public Test1ViewController (IntPtr handle) : base (handle)
{
}
A general explanation of the error message you are seeing:
Such issues are, 99% of the time, related to a managed instance with no
reference. At some point the GC will collect it and it will crash whenever some native code tries to callback into the (now freed) managed instance.

Related

How to insert and add custom rows in customization?

I'm trying to write some code for a customization with an action button, AddFollowUp to Leads. I want to:
update a custom field called UsrNextFollwup -> how do I access the custom field in the object?
I can update objects I find with PXSelect<> but how I can insert new objects? eg if I create Contact myContact=new Contact(); //set properties, etc -> how do I insert it?
How can I find the current user's ID? I can get the current lead from Contact curLead=Base.LeadCurrent.SelectSingle() but I also want something like #me function.
My code:
public class LeadMaint_Extension:PXGraphExtension<LeadMaint>
{
public PXAction<PX.Objects.CR.Contact> AddFollowUp;
public PXSelect<CRActivity> Task;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Add FollowUp")]
public void addFollowUp()
{
Contact curLead=Base.LeadCurrent.SelectSingle();
DateTime dueDate = DateTime.Now;
curLead.CreatedDateTime = dueDate.AddDays(14); //works great
curLead.UsrNextFollwup = dueDate.AddDays(14); //doesn't work
}
}
In Acumatica custom fields are declared via DAC extensions. To access the DAC extension object, you can use the following methods:
The GetExtension() generic method available for each DAC instance:
ContactExt contactExt = curLead.GetExtension<ContactExt>();
The GetExtension(object) generic method declared within the non-generic PXCache class
ContactExt contactExt = Base.LeadCurrent.Cache.GetExtension<ContactExt>(curLead);
or
ContactExt contactExt = Base.Caches[typeof(Contact)].GetExtension<ContactExt>(curLead);
The GetExtension(object) static generic method of the PXCache generic class
ContactExt contactExt = PXCache<Contact>.GetExtension<ContactExt>(curLead);
To insert, update or delete a DAC record, one should invoke Insert, Update or Delete method on appropriate PXCache instance (or a data view, which simply redirects the call to PXCache -> ShipmentLines.Insert(line) is an equivalent to ShipmentLines.Cache.Insert(line) statement). For instance, to insert a data record into the cache in code, you invoke the Insert() method of a data view as follows:
ShipmentLine line = new ShipmentLine();
line.ProductID = card.ProductID;
...
ShipmentLines.Insert(line);
Some application settings, such as BranchID, UserID and UserName are accessible via Accessinfo property of the PXGraph class. The Accessinfo property returns an instance of the AccessInfo DAC - AccessInfo.UserID will return ID for the current user. To access the Accessinfo property from a BLC extension, use Base.Accessinfo statement
Starting ver. 5 Acumatica introduced runtime compilation, which allowed to publish customizations without a mandatory restart of IIS app pool when there are no dlls included with any of currently applied customization projects. Before runtime compilation was released, customization manager created all code files in App_Code\Caches folder of the website. Asp.Net runtime takes care of any code files created in App_Code\Caches folder, immediately compiles them and restarts IIS app pool to also immediately bring all changes on your Acumatica website. The beauty of this approach is that all classes declared in any file located under App_Code\Caches folder, are available with VS IntelliSense and never highlighted with red underlines as potential issue. The only drawback - every time you make any change inside App_Code\Caches folder, IIS app pool restarts (same thing as if you re-compiled a dll located in Bin folder) and it takes some time for your website to reboot so you can test your changes.
With runtime compilation in place, Acumatica created all code files in App_RuntimeCode folder of the website. Now it's Acumatica's responsibility to compile all code files from App_RuntimeCode folder into an assembly and load it at runtime without a restart of IIS app pool. With this approach you don't need to wait for your website to reboot every time you make some changes in your customization. On the other hand, sometimes runtime complication doesn't always properly clear up what was done in your previous code files and time to time, it might be necessary to manually recycle app pool or restart IIS on your developer machine to make sure Acumatica loads only actual code from the App_RuntimeCode folder. Another drawback is lack of support by VS IntelliSense: all classes declared in any file located under App_RuntimeCode folder is never suggested by IntelliSense and always highlighted with red underlines as potential issue, though both yourself and Acumatica are confident, that everything is fine and all files will compile with mo issues.
To have all customization files automatically created in App_Code\Caches folder, just disable runtime compilation on your development website by adding following key to appSettings in web.config file:
<add key="UseRuntimeCompilation" value="false" />

How to avoid constructor to be call twice when a page is define twice in a page

I am creating a winRt app. In which I am having a Home.xaml page which having a another page called Market.xaml. So for snapped mode the same code is repeated.
Now my itemListView (used for snapped) and itemGridView (for full view) both have this page (Market)
<views:Market x:Name="viewMarket"/>
And the constructor of this page is called twice which I not want.
So do I use some flag kind of thing or some better approach is there.
Thanks
So, let's talk about this:
XAML is basically a varying syntax to C#. So, when XAML references a control like your views:Market with <Views:Market />, you are actually putting in something like new Views.Market() in both places. Basically, invoking the class twice. Should the constructor not fire twice, the time-space continuum would split in half. Dogs and cats living together, the whole 9 yards.
But, more fundamental here, what is the purpose of the constructor in C#, or in a XAML class? Is to do expensive things that you would not want to repeat? No. The reason for this is because the completion of the constructor is necessary before the UI thread is released and allowed to render the control. The resulting effect is a UI hang.
Moreover, the C# constructor is a synchronous method. It cannot properly invoke or hold asynchronous operations. This means long-running or expensive tasks that should be invoked immediately, should not be invoked in the constructor because it would also require them to be synchronous and UI-blocking. It is because of these last two points I suspect your constructor is being misused.
The solution is in the XAML framework. The XAML Page pipeline includes the constructor (since it is a C# class and they all have it) but it also includes a Loaded event. In many cases, the hard work necessary to fill page controls is in the Loaded handler. This allows the page to render properly, then starts the long-running action that will ultimately and asynchronously update control content.
In WinRT, the Page pipeline also includes an OnNavigatedTo() virtual method in the base that you can override to the same effect. In the override you can include the hard work of talking to a service, deserializing from a file, or whatever you need to make your UI work. Both the Loaded event and the override can be asynchronous, and neither prevent rendering by freezing the constructor.
But, there's another thing to consider since we're in C# and that the rather common pattern called singleton that allows for us to reference a type in two different contexts but without creating a brand new class. This is accomplished by making the class constructor private, but exposing a public property usually called Instance that returns a single, shared instances in some static place.
That might solve your problem already. Then again, none of that is probably what you need. Assuming you already know all that, the quick answer is you can't prevent a constructor because a constructor is necessary to create a new instantiation of any class, including a XAML view. Instead, whatever you are trying to prevent being double might need to be a combination of the discussions above. An offloaded method, and a static reference to prevent duplicate efforts.
Something like this:
public class Market : UserControl
{
public Market()
{
Loaded += Market_Loaded;
}
static bool AlreadyLoaded = false;
void Market_Loaded(object sender, RoutedEventArgs e)
{
if (AlreadyLoaded)
return;
AlreadyLoaded = true;
// TODO: your work
}
}
But that might not do it for you because the static variable is scoped too large. Instead, you can control if it does the big operation with a dependency property you add to your control. With a boolean dependency property set to false, the second control knows not to do something. With it set to true, the first knows to go ahead. And, so on. This prevents all future use of the view or user control in your app from thinking it should not run because of the static property in the above solution. Then again, that might be perfect.
Best of luck!

Adding UIWebView to second (not first) Storyboard view controller

Getting started with xCode 4.6.3 and I'm running into a hiccup.
I've built a simple app using the UIWebView to display a local HTML file and it's contents. I used that to debug any issues with the HTML and/or image displays and I'm all set.
Now I need to recreate that within a larger project I've built with storyboards for all my navigations between multiple view controllers. My issue comes when I'm trying to control-click drag from the WebView into the ViewController.h code below the #interface like many tutorials show, and that worked fine within my smaller single view controller app. It won't do it. I know I'm missing something obvious here. Am I going to have the set up these screens (I have multiple ones to do this same way) as separate xib files and add them into my main project?
Thanks for any help and clarification.
-Chris
You can create a class called for example myWebViewController and in Interface builder add a UIWebView to it. The control+drag to the header file will work.
Every time you want a UIViewController that has a browser in it, define its class as myWebViewController in Interface Builder.
Try not to repeat code. If you see UIViewControllers or any other UIView...that do the same thing, you can group them into a class that you use over and over.

ViewModel navigation with TabBarPresenter

I have made a HomeViewModel which contains some other ViewModels to be presented in a TabParPresenter. This works fine and the ViewModels associated Views are presented correctly in their corresponding tabs. However on of the ViewModels have a check in the ctor that tells it in when some conditions apply it needs to navigate to SettingsViewModel , which is not a part of the ViewModels contained in HomeViewModel.
The navigation event gets caught by the TabBarPresenterHost, which is simply the Presenter of the application and if a TabBarPresenter is present and not null it is passed to the TabBarPresenter.ShowView() method. All this happens before the TabBarPresenter is done loading and SelectedViewController is set in ViewDidLoad. Hence the TabBarPresenter relies on using the SelectedViewController to push new Views I obviously get a Null Reference Exception.
In short what I want is:
if (conditionForShowingHome == true)
GoToHome();
else
GoToSettings();
Then when inside SettingsViewModel I have set the stuff I need when going back you return to HomeViewModel.
What breaks this is that the ViewModels are loaded before the View is done loading and the navigation event is executed before the View is done loading. Any ideas how to go around this?
I'm afraid that putting this code inside a ViewModel constructor is likely to lead to problems.
The ViewModel constructors are called during navigations - and not all platforms will support starting new navigations while existing ones are still in progress.
To workaround this, I personally opt to put this type of behaviour in the code before the navigation.
In the case of a normal navigation, this can go inside an MvxCommand execution handler.
In the case of application startup, I do this in a custom app start - see some notes in https://speakerdeck.com/cirrious/appstart-in-mvvmcross

Assigning individual View Models to Nested Views?

I have a MainView which has an associated MainViewModel in my WPF application, assigned via its contructor.
App > start up uri > MainWindow.xaml
public MainWindow()
{
InitializeComponent();
var viewModel = new MainViewModel();
DataContext = viewModel;
}
My MainView holds as many as four nested views or child views who are hidden and displayed based upon the button that has been clicked on the MainView. So we toggling the visibility property vi a binding which gets updated via command bindings assigned to each button on the MainView.
Each nested View does not have an associated ViewModel, all bindings found on child views find their information in the MainViewModel. So binding system ends waling up the UI tree of the app to find out that the parent 'MainView' has an associated ViewModel.
So overall there is 'ONE' -> ViewModel. This seems to work fine and but as expected this VM has gotten to big and needs re-factoring. It holds information that contextually it should not. But this is a proof concept application. So i decided to keep it simple and make sure it was do-able.
PROBLEM:
When i tried assigning a empty view with an empty view model I noticed binding errors in the output window and as expected weird and broken behaviour. Which makes no sense ... Is there a more clear and concise way of letting WPF know how to handle any bindings it finds in a nested view control? I thought if each view's constructor assigned itself a corresponding VM as shown above, then it should work as this logically makes sense. Unfortunately all buttons on the MainView stop working when the corresponding view it is designated to switch on and hide the others has an associated ViewModel. On some buttons it works and the others it does not? This is really weird?
As mentioned in my answer above, the problem was that WPF binding system was struggling to to resolve bindings at run time. The main view has its associated view model instantiated and assigned via the Main View contructor and this pattern is repeated for all nested views that the MainView also houses.
By default, I tend to use the implied binding syntax which means that without explicitly specifiying a source the binding system will try to resolve the name you supply in the binding. So it's all implied and nothing is explicitly set!
Upgrading each nested view to have its own view model makes this auto discovery/resolution of bindings go a little crazy and I have not explicitly told the binding system where to find the property I am looking for hence the output window binding errors.
This leads to unexpected behaviour as the output window was telling that it was trying to resolve binding expressions in nested views --> viewmodels. When in actual fact that VM it is looking in, IS EMPTY!
So clearly the binding system is good when you do not explicitly set a source property inside the binding syntax. It is clever enough to find things on its own. In my case it needed some extra help, as it was unsure as to where to find things.
SOLUTION:
Remove the constructor declaration for the MainViewModel in the MainView constructor.
Scope in an xmlns for ViewModels namesapce into your MainView.xaml
Create a window resource inside the MainView .xaml
Give the resource a key.
Upgrade all your bindings in the MainView xaml file to include source property.
Give the source property a static resource binding that points to your ViewModel key value set up in step 4.
Only do step 6 for bindings who refer to the ViewModel that is associate with the MainView.
All nested views are to be left alone, they should handle their own bindingds in their own xaml files. The MainView simply instantiates them and places them onto the UI. For me this was the case, I did not have any more bindings concerning my nested views. All Bindings that lived on the MainView.xaml file referred to data in the MainViewModel.cs. This makes alot easier when viewing your problem.
For some reason the editor was being awkward so I chose to omit any sample code but the steps above are descriptive enough to follow the steps that I took. Above is what worked for me.
ANOTHER WAY OF SUMMING UP THIS PROBLEM
Most books teach the shorter binding syntax
What happens when more than one data context is available?
How is the binding system supposed to know how to resolve your short hand binding expressions.

Resources