I know that bindings in MvvmCross get hooked up initially when we call SetContentView. However, I am dynamically creating a new view and the bindings from it are not being hooked up. Is there a way to get the MvvmCross bindings to hook up for views created after SetContentView was initially called?
In my example specifically - I am coding for the Google Glass client and implementing multiple cards. When certain information is sent to Glass, I create a new card and inflate an xml file for the new card's view but the bindings are not getting hooked up.
Code to create the new card:
_cardScrollAdapter.AddItem(LayoutInflater.Inflate(Resource.Layout.new_panel_view, null))
Portion of XML that creates the binding:
local:MvxBind="Bitmap BitmapConverter(PanelViewModel.Image); Visibility Visibility(PanelViewModel.ShowImage)"
The issue is related to the fact that you are passing a View inflated using the Android LayoutInflater.Inflate method, instead of using the MvvmCross BindingInflate method. With a using Cirrious.MvvmCross.Binding.Droid.BindingContext; at the top of your file, the following should work:
_cardScrollAdapter.AddItem(this.BindingInflate(Resource.Layout.media_panel_view,null));
Related
I am using:
C#
MvvmCroos.Core 5.6.3.
MvvmCroos.Platform 5.6.3.
Microsoft.NETCore.UniversalWindowsPlatform 5.2.2
VS 2015
Windows 10 target version: Build 14393
For Wpf approach MvvmCross supports CreateView behavior which based on MvxViewModelRequest returns a view as a FrameworkElement type.
Example:
var request = new MvxViewModelRequest(viewModelType, parameterBundle, presentationBundle, null);
var view = Mvx.Resolve<IMvxSimpleWpfViewLoader>().CreateView(request);
Unfortunately, CreateView and IMvxSimpleWpfViewLoader equivalents don't exist in UWP land. How do I achieve same functionality? Any suggestions?
In UWP a views is a Page. Pages are usually not created directly (although it is still possible), but rather displayed in the context of a Frame, which acts as a container and keeps track of navigation stack and navigation parameters for each page. With the container the Page also gets notified when it is navigated to and from using NavigatedTo and NavigatedFrom events.
If you check out the MvxWindowsViewPresenter code, you can see how navigation is handled in UWP. Instead of creating an instance of the page we use Frame.Navigate and pass in the type of the page that we want to navigate to and the Frame takes care of the lifetime of the page including its instantiation.
Currently, we have the following situation:
Account entity contains online_status field, which can have either offline or online value. And we have an entity view, which shows only online accounts.
case1:
I open the view. It's empty for now;
I open an account form in another window and manually change online status from offline to online;
After clicking save, grid in view auto updates and starts showing this account
case2:
I change online status using SDK:
using (var proxy = CreateCrmProxy(broker))
{
proxy.EnableProxyTypes();
var crmAccount = proxy.Retrieve(Account.EntityLogicalName, aggregateId, new ColumnSet()) as Account;
crmAccount.OnlineStatus = //new online status;
proxy.Update(crmAccount);
}
CreateCrmProxy method creates an instance of OrganizationServiceProxy class.
In this case, online_status field updates successfully, but grid in view stays in an old state and I need to press "refresh" button in order to see valid information.
Is it possible to fire view auto update, using the technique from case2?
Thanks in advance!
No, you cant do this with a plugin, since plugin is purely backend and sub-grids are a front-end UI construct. Its possible you could do something hacky with calling a RetrieveMultiple after you make the update, but there wouldn't be any way to force the view to update itself.
A better option in your circumstance would be to trigger the change via javascript (a REST or SOAP Call would suffice), so that once the update is complete, then you can call a control.refresh. It would get a bit trickier on a dashboard because you wouldn't have a form to load the javascript with and the view would be in a different pane, but you could do something with a web resource and use the parent context.
I'm new in mobile app development. I'm using Xamarin to develop Android applications. In the hello world app in the OnCreate method I see the following code:
Button button = FindViewById<Button>(Resource.Id.MyButton);
So I'm trying to create my own button the same way. I create the button in the designer and inside OnCreate method put the line:
Button myOwnBtn = FindViewById<Button>(Resource.Id.MyOwnBtn);
That gives me an error that there is no MyOwnBtn. Then I'm looking the code of Id class and see there a line like:
public const int MyButton=2123344112;
If I put there the line:
public const int MyOwnBtn=2123344113;
Everything works fine. But as I understand it should be generated automatically or it will be a little bit difficult to put there a unique number for each control.
Can anybody tell me what I am doing wrong? And how does FindViewById() work?
You have to give the id MyOwnBtn to the Button that you created in the designer.
findViewById is a method of the View class and it looks for a child view having the id that you provided in the argument.
From official documentation:
Look for a child view with the given id. If this view has the given id, return this view.
MyButton id is not a const value, It will change every launch.
The Activity or ViewGroup's findViewById() method returns a view that already has an id. The findViewById() method should be used in conjunction with XML layouts to provide a reference to the View that was defined in the XML file.
Edit: Not entirely sure if my answer is relevant to Xamarin. I apologize if I have mislead people, I am referring to Java Android application development.
When you declare a button in your .xml file, you should set an id for it (Usually it is done using string.xml file). After that, R.java will be updated automatically and set a number to your declared id and you can access your button by that id like what you have done.
It will try to find it from the XML file that you inflate. So make sure you inflate the correct xml file. This code inflates the xml:
SetContentView (Resource.Layout.MainLayout);
Even if you got the correct id created in a xml file, if you don't inflate it first, the system won't be able to find that view since it is not inflated.
I have 2 questions regarding a tutorial that I am going through.
Q1.
Through the tutorial they use a datasource
Using the data in the app
To use the data in the app, you create an instance of the data source
as a resource in App.xaml. You name the instance feedDataSource.
BR211380.wedge(en-us,WIN.10).gifTo add a resource to an app
Double-click App.xaml in Solution Explorer. The file opens in the XAML editor.
Add the resource declaration, <local:FeedDataSource x:Key="feedDataSource"/>, to the root ResourceDictionary, after the
MergedDictionaries collection.
and then they use it in the OnLaunch method.
var connectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (connectionProfile != null)
{
FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
if (feedDataSource != null)
{
if (feedDataSource.Feeds.Count == 0)
{
await feedDataSource.GetFeedsAsync();
}
}
}
I am wondering why do they store it in resource? Wy not just create an instance of the class and get the results from it?
Q2.
Later down the article they use this datasource items with "grid view items". I seen this done in their other template projects. I am wondering is there the standard way of making your interface?
At first I thought maybe just drop some image buttons on the screen and hook up their click events but now I am not sure.
The XAML Resource essentially does create an instance for you and makes it available in the Resources collection, so you could instantiate the class yourself. Having it as a resource keeps this object around and makes it accessible across the various pages in your application. You could certainly create the class explicitly, and if you enforce the singleton pattern on it, it would be semantically equivalent.
I'm not sure I see the context of your second question in the tutorial, but in general the pattern you are seeing is Model-View-ViewModel (MVVM), which is the de facto standard pattern for Windows Store apps. feedDataSource is providing the model and portions of that are assigned to DefaultViewModel, which is the DataContext for all of the binding markup in the XAML pages, which are the views. The idea behind this to separate your data from your model, so that when you do things like load a new data feed, etc., all you need to do is change the data source, and all of the data binding markup will automatically reflect the new data in your user interface.
If you find yourself writing code that looks like TextBox.Text = "My text", then you're deviating from the pattern.
I'm trying to learn monotouch at the moment, and following the learn monotouch book by Mike BlueStein. Not a bad book, but it's slightly outdated since xcode 4 (i believe) and a newer version on monotouch has come out.
Anyways, in my project I have a controller and a xib file. I also have a custom view (e.g. myview : UIView), that overrides the draw method. I want to show my custom view next to or on top of the view defined in the xib file. How do I do this?
In the controller, If I override the LoadView method, and set the View to an instance of my custom view, then I can see it, but I loose everything defined in the xib file. If I try to add as a sub view, it does not appear at all.
What am I missing? If the question is not clear, please ask me, so I can clarify.
Cheers.
Follow the following steps to use a custom view in a XIB:
First, decorate the view with the RegisterAttribute:
[Register("MyView")]
public class MyView : UIView
{
}
and implement the following constructor:
public MyView(IntPtr handle) : base(handle) {}
This constructor is needed for when the runtime will try to recreate the view after it has been destroyed by a memory warning. After you have created your custom class:
Open the XIB in Xcode (always by double-clicking on it through MonoDevelop) and add a UIView where you want it.
In Xcode, set that UIView's class to MyView (or whichever name you passed to the RegisterAttribute):
Compile-Run.
EDIT:
Do not override LoadView for controllers that are loaded from a XIB. LoadView is meant to create the controller's view when that controller's view is not loaded from a XIB.
Thanks Dimitris, great answer.
For those who get confused like me, here is the simplist procedure to add and use a Xib file as a partial / subview:
Add a new Xib File in MonoDevelop (ie LoginView.xib)
Add a new (partial) Class, this will be the custom class (The Code-behind file let 's say) for the view. Give it any name "LoginView.cs")
Add the Attribute (RegisterAttribte) and the Constrctor as exaplain above by
Dimitris.
Double click the LoginView.xib to open it in XCode IB. Then Change the Custom Class Attribute of the xib file to point to your "code-behind file" (ie LoginView.cs)
Add any outlets or action if you need. MonoDevelop will generate a .designer file and attach it to your code-behind file, this is where you can see all your outlets and actions.
In your controllers where you want to add this view, load your .xib file as follows:
var views = NSBundle.MainBundle.LoadNib("LoginView", this, null);
LoginView loginView = Runtime.GetNSObject(views.ValueAt(0)) as LoginView;
mainLayout.AddSubview(loginView);
// where mainLoyout is the placeHolder in my main ViewController
These three lines are based on flexaddicted answer here