MvxImageView, can't bind ImageUrl to local resource - xamarin.android

I'm using MvvmCross 3.0.14 with Xamarin.Android.
I have an MvxImageView that I can get to display a particular local graphics resource if I specify the image directly (without binding) using android:src:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
android:src="#drawable/Card_kh"/>
But I can't get the same image to show up using local:MvxBind:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl 'res:Card_kh'"/>
This does not work. MvxAndroidLocalFileImageLoader.LoadResourceBitmap logs a trace message indicating that 'Card_kh' was not a known drawable name. It's encouraging that it got that far -- at least I know that the intended consumer of this information did get it. But apparently I have not provided that information in the correct format.
Taking it one step further, my actual goal is to have my ViewModel determine what resource should be used, e.g.
class MyViewModel : MvxViewModel
{
public string SomeImagePath { get { return "res:Card_kh"; } }
}
and
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl SomeImagePath"/>
What do I need to do to have an MvxImageView bind to a view-model determined local resource image?

The problem was only capitalization in the resource name. Although the image filename starts with a capital C, and the android:src attribute works with a capital C, the MvxBind of ImageUrl requires a lowercase c:
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl 'res:card_kh'"/>
This also solves the problem when the source of the ImageUrl value is a viewmodel property:
class MyViewModel : MvxViewModel
{
public string SomeImagePath { get { return "res:card_kh"; } }
}
and
<Mvx.MvxImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImageUrl SomeImagePath"/>

The previous answer is not working anymore since MVVMCross v6.0.0.
As described here https://www.mvvmcross.com/documentation/upgrading/upgrade-to-mvvmcross-60 MvxImageView has been removed from the API.
The newest alternative is now https://github.com/luberda-molinet/FFImageLoading/wiki/MvvmCross.
This nuget package "Xamarin.FFImageLoading" must be added in order to make the code below work.
<ffimageloading.cross.MvxCachedImageView
android:layout_width="100dp"
android:layout_height="75dip"
android:layout_weight="1"
local:MvxBind="ImagePath SomeImagePath"/>

Related

How to bind a UITableView to a List<string> using MvvmCross in Xamarin iOS

I am working on an application that is Xamarin Native using MvvmCross. I have spent the afternoon looking for an example of how to bind a list of strings to a table view in iOS but every example is binding to a List of Models and not string. I know this can be done in android...
<Mvx.MvxListView android:id="#+id/lvErrors"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/lblCaption"
android:layout_alignParentLeft="true"
local:MvxBind="ItemsSource Errors" />
where "Errors" is a List of strings. However trying a similar approach in iOS fails to load data.
var set = this.CreateBindingSet<ViolationDetailsView, ViolationDetailsViewModel>();
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText Errors;");
ErrorsTableView.Source = source;
set.Bind(source).To(vm => vm.Errors);
set.Apply();
Can anyone point me in the right direction to find an example of this?
I ended up finding the answer here. "If you want to bind to the whole string object then use a . period for whole object binding."
So...
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText Errors;");
became...
var source = new MvxStandardTableViewSource(ErrorsTableView, "TitleText .;");
I knew it was something simple.

local:MvxLang failed to bind the resource text to TextView when it is part of itemtemplate of MvxListView in Xamarin app

Issue:- local:MvxLang failed to bind the resource text to TextView when it is part of itemtemplate of MvxListView in Xamarin app using localization feature in MVVMCross.
My application is Xamarin.android, using MVVMCross, used Localization feature of MVVMCross with resx file.
Running sample can be found here:https://github.com/pallaviak1/RestaurantBilling.Droid
I am getting localized string through code using below syntax in viewmodel (AllBillsViewModel) BillClickedCommand:-
_dialogService.ShowAlertAsync( string.Format(TextSource.GetText("InformationReceivedMessage"), bill.CustomerEmail, bill.AmountPaid), TextSource.GetText("InformationReceivedHeader"), TextSource.GetText("InformationReceivedButtonText"));
Also my main view page where local:mvxLang is button attribute, which shows button text from resource of selected culture, also works well.
<Button ... local:MvxLang="Text ViewBillsResourceText" local:MvxBind="Click NavigateAllBills" />
Problem:- However when I am using MvxLang in controls which are part of item template of MvxListView control the localized string is blank (not populated).
file:- RestaurantBilling.Droid\RestaurantBilling.Droid\Resources\layout\ListItem_Bill.axml
The control which is part of item template view looks like below:-
<TextView android:layout_alignParentBottom="true"
android:layout_marginLeft="50dp"
android:layout_marginRight="16dp"
android:layout_width="90dp"
android:layout_height="wrap_content"
local:MvxLang="Text CustomerEmailTextView" />
The mail list control looks like below:-
<Mvx.MvxListView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
local:MvxBind="ItemsSource AllBills; ItemClick BillClickedCommand"
local:MvxItemTemplate="#layout/listitem_bill" />
CustomerEmailTextView resource key is present in resx files as Name: AllBillsViewModel.CustomerEmailTextView, value : "US Customer Email".
Just to add, my Localization code is as below:-
Resource files are present in library MVVMCross.Localization, whose reference is added in RestaurantBilling.core library as well as android project.
code in core, App.cs file as below:-
Mvx.RegisterSingleton<IMvxTextProvider>
(new ResxTextProvider(Strings.ResourceManager, currentCulture));
BaseViewModel has below code:-
public IMvxLanguageBinder TextSource =>
new MvxLanguageBinder("", GetType().Name);
Getting warning in visual studio output window as below:
[0:] MvxBind:Warning: 9.78 Unable to bind: source property source not found Property:TextSource on Bill
02-10 07:41:52.020 I/MvxBind ( 4357): 9.78 Unable to bind: source property source not found Property:TextSource on Bill
I could not find enough help on MVVMCross formal website, also could not find much discussion points on same. The same thing is working in sample downloaded "My Trains" when referred from pluralsight training.
Please help.
my problem is resolved. ref link: How to bind ItemClick in MvxListView in MvxListView
This link issue is somewhat similar. I resolved the issue in below way,
whatever TextSource property I have added in viewModel, I need to put in Bill.cs class which is model
public IMvxLanguageBinder TextSource
{
get {
//Mvx.Trace("****************TextSource get in bill.cs**************************");
return new MvxLanguageBinder("", GetType().Name);
}
}
Then, the resource text key looks like below:-
Bill.CustomerEmailTextView
This is kind of workaround, actually BaseViewModel has TextSource property however it is not useful in case of item template case.
Please let me know if you have better solution because we are kind of mixing viewmodel and model properties.

Android MapFragment as custom control in MvvmCross

I'm working on a project in which I can use MapFragment or SupportMapFragment as a custom control.
I tried to mix custom control(N-18) and Fraggle(N-26) tutorial but I can't make it work.
My Custom Control Class:
public class CustomMapView : MvxFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.CustomMapViewLayout, null);
}
}
My CustomMapViewLayout.axml
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
In the FirstView.axml I reference the CustomMapView:
<cc.CustomMapView
android:layout_width="match_parent"
android:layout_height="match_parent" />
(I use the ViewNamespaceAbbreviations in the Setup.cs)
When I try to deploy I get these errors:
MvxBind:Error View Type Not Found - cc.CustomMapView (I'm sure the namespace is correct)
Android.Views.InflateException:Loading...
Is there anybody who managed to solve this kind problem?
As far as I know, fragments have to be used within FragmentActivity parents and have to be loaded either using the fragment xml tag or using one of the (support) fragment manager methods for dynamic loading within a parent viewgroup.
The Mvx code which is reporting View Type Not Found - cc.CustomMapView definitely won't work - it's looking for a class which inherits Android View in that namespace, not looking for a Fragment.
There may be ways to write more 'dynamic' fragment xml code - but none of the mvvmcross contributors have unearthed any of these yet. For now, I think you'll have to use the Fragments more 'conventionally' - like the ways shown in the N=26 sample

MVVMCross - MvxBind: Combine/Concat Properties

I have a little question:
In my axml Designer I have something like this:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="{'Text':{'Path':'FirstName'}}" />
That works fine, but how could I combine/concat 2 Properties (or even more)..
So something like: FirstName + SecondName (2 Properties in one Text)
This is a standard Mvvm question. I think it came up a lot in the early years of Wpf - I think there are lots of ideas around about multiple dependencies.... I've not implemented any of these yet...
If you want to do this, then you could use:
(1) expose a combination property on the ViewModel object:
public string FullName
{
get
{
return FirstName + SecondName;
}
}
if you do this, then you'll need to make sure that when you RaisePropertyChanged("FirstName") or RaisePropertyChanged("SecondName"), then you also RaisePropertyChanged("FullName")
(2) Use a converter to combine the names together:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="{'Text':{'Path':'','Converter':'MakeFullName'}}" />
Note that the Converter here takes the parent object as its input parameter.
Note that in this case, if FirstName or SecondName change then the text view might not get updated :/
(3) You could use multiple TextViews in the UI - each one bound to the necessary bit of text.
(4) You could use a single textview and use C# level binding - e.g. in the View use code like:
ViewModel.PropertyChanged += (s,e) => {
if (e.PropertyName == "FirstName" || e.PropertyName == "SecondName")
{
this.FindViewById<TextView>(Resource.Id.XXX).Text = ViewModel.FirstName + ViewModel.SecondName;
}
}
If you think multi-dependency bindings are an important requirement, please log this as an issue (feature request) in https://github.com/slodge/MvvmCross/issues - or maybe even just fork the code and add them :)

Silverlight 3: How to store PathGeometry in a resource library

I'm having isues trying to access a PathGeometry resource in a Resource Library in a silverlight 3 app
Ive created a resource file called Geo.xaml
in my app.xaml i link to this file
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Components/Resources/Geo.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
in my resource file i have the following line which has the geometry for a simple box
<PathGeometry x:Key="CloseCross">M0,0 L188,0 L188,161 L0,161 z</PathGeometry>
and then in my MainPage.xaml i have a path trying to use that resource
<Path Data="{StaticResource CloseCross}" Stretch="Fill" Margin="10,10,0,0" Width="100" Height="100" UseLayoutRounding="False" Fill="Red"/>
and in Blend 3 (RC) it all looks fine, the path takes on the geometry and displays fine, the problem is when i build it and view it in browser i get the following error
Attribute {StaticResource CloseCross} value is out of range. [Line: 8 Position: 14]
I discovered a semi work around but even that has issues, i can create a style for target type Path and use a setter to set the Data property of the Path
<Style x:Key="PathStyle1" TargetType="Path">
<Setter Property="Data" Value="M0,0 L188,0 L188,161 L0,161 z" />
</Style>
The problem with this is that when I apply that style, the geometry isnt displayed in blend, the path is there in the hierachy tree but is not visible on the canvas but when i build and view it in a browser, its all good...
can anyone help me understand why I cant seem to put path geometry in a resource file (or in fact anywhere)
One problem is that in Silverlight you cannot store Paths within the ResourceDictionary. I would put the Path coordinates within a string resource, and then use http://StringToPathGeometry.codeplex.com to create the paths.
It is actually possible to store a path in a ResourceDictionary, the trick being to store it as a string.
However, the issue with this is that you get no design time suport if you do this, although at run time, it looks great.
The workaround for getting design time support in SL 5 is to store the path as a string in a code file, then using binding to get to the path data. This is the only way to get your path to show up at design time.
For example, say you have a toolbar button and you want to use a path as it's icon:
<c1:C1ToolbarButton x:Name="SaveChanges">
<Path Margin="5"
Data="{Binding SaveIcon,
Source={StaticResource iconTheme}}"
Stretch="Uniform" />
</c1:C1ToolbarButton>
Now you have your path bound to a class which implements INotifyPropertyChanged:
//A class for storing Paths which are turned into icons.
public class IconTheme : INotifyPropertyChanged
{
private string _saveIcon =
"M10.280033,48.087753L10.280033,54.397381 50.810078,54.397381 50.810078,48.087753z M15.900046,6.4432963E-05L23.693047,6.4432963E-05 23.693047,15.900064 15.900046,15.900064z M3.4200456,0L10.280033,0 10.280033,19.019096 50.810078,19.019096 50.810078,0 58.300069,0C60.190087,0,61.730004,1.5399642,61.730004,3.4298871L61.730004,59.237114C61.730004,61.137043,60.190087,62.667,58.300069,62.667L3.4200456,62.667C1.53003,62.667,1.896733E-07,61.137043,0,59.237114L0,3.4298871C1.896733E-07,1.5399642,1.53003,0,3.4200456,0z";
public string SaveIcon
{
get { return this._saveIcon; }
set { this._saveIcon = value;
NotifyPropertyChanged("SaveIcon");
}
}
void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Lastly, you need to create an instance of the class in your App.xaml file:
<Assets:IconTheme x:Key="iconTheme" />
Now you can bind to this anywhere in your app and see the path at design time. I would prefer to have the path in Xaml, but not being able to see it at design time can be a significant drawback. Furtheremore, if I wanted to customize the Icons at runtime, I could now do so in the IconTheme class and the changes would instantly show up in the app.

Resources