Xamarin forms : Content View doesn't display in content page - xamarin

Am trying to Load a Content View in a Content page. When I run the code it doesn't hit my Content View. I am assigning two Bindable parameters from my content page.
Content Page:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:templates="clr-namespace:G2.Scanner.Views.Templates"
xmlns:viewModelBase="clr-namespace:G2.Scanner.ViewModels.Base;assembly=G2.Scanner"
xmlns:telerikPrimitives="clr-namespace:Telerik.XamarinForms.Primitives;assembly=Telerik.XamarinForms.Primitives"
xmlns:local ="clr-namespace:G2.Scanner.Views.Transaction"
x:Class="G2.Scanner.Views.Transaction.TransactionView"
viewModelBase:ViewModelLocator.AutoWireViewModel="true">
<local:GenerateScreen x:Name="generateScreen" ControllerName="{Binding ControllerName}" IsBusy="{Binding IsBusy}"/>
</ContentPage>
Content View:
public partial class GenerateScreen : ContentView
{
#region BindableProperties
public static readonly BindableProperty ControllerNameProperty = BindableProperty.Create("ControllerName", typeof(string), typeof(GenerateScreen));
public static readonly BindableProperty IsBusyProperty = BindableProperty.Create("IsBusy", typeof(bool), typeof(GenerateScreen));
#endregion
#region Properties
public string ControllerName
{
get { return (string)GetValue(ControllerNameProperty); }
set { SetValue(ControllerNameProperty, value); }
}
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
#endregion
public GenerateScreen()
{
InitializeComponent();
DesignScreenAsync();
}
public async void DesignScreenAsync()
{
IsBusy = true;
// Some Design code..
#region render
scroll = new ScrollView
{
Content = layout
};
TransactionElements.Children.Add(scroll);
#endregion
IsBusy = false;
}
Content View accepts two bindable property and is used at the time of load.
Content View Xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="G2.Scanner.Views.Transaction.GenerateScreen">
<ContentView.Content>
<StackLayout x:Name="TransactionElements"/>
</ContentView.Content>
</ContentView>
I want this view to be rendered at the time content page is loaded.
I figured out that this works if I don't use bindable properties in content view. But as per My requirement ControllerName and IsBusy in ContentView Class Should be Bindable Property.
Any Help why it's not hitting this View.

Thank you all for taking your time. I actually found a solution for myself.
What actually went wrong was in two places.
The bindable properties will be only set after the initialization of the class. So if we call the DesignScreenAsync method in the constructor which takes the value of ControllerName will obviously have null. the solution is to call the method in ControllerName's PropertyChanged method.
Here is the code:
public static readonly BindableProperty ControllerNameProperty = BindableProperty.Create(nameof(ControllerName), typeof(string), typeof(GenerateScreen),default(string), propertyChanged: OnControllerPropertyChange);
private static void OnControllerPropertyChange(BindableObject bindable, object oldValue, object newValue)
{
((GenerateScreen)bindable).DesignScreenAsync();
}
Notice that I have used BindableObject to call the method. This is to call the method from the same instence.
The reason why contentView was not hitting, is that I didn't set a default value for the bool IsBusyProperty, so it is important to set the default value for a bindable property.
Here is the code:
public static readonly BindableProperty IsBusyProperty = BindableProperty.Create(nameof(IsBusy), typeof(bool), typeof(GenerateScreen), default(bool), defaultBindingMode: BindingMode.TwoWay);

Defining an async void method is most of the time a bad practice.
To avoid this and probably solve your problem, you have 2 solutions depending on your need.
1) If DesignScreen only builds your UI without intensive call, you must execute it synchronously:
public GenerateScreen()
{
InitializeComponent();
DesignScreenAsync();
}
public void DesignScreen()
{
IsBusy = true;
// Some Design code..
#region render
scroll = new ScrollView
{
Content = layout
};
TransactionElements.Children.Add(scroll);
#endregion
IsBusy = false;
}
2) If you have intensive calls that need to be awaited. Perform intensive calls and and update UI using Device.BeginInvokeOnMainThread:
public async void DesignScreenAsync()
{
IsBusy = true;
await ApiIntensiveCall();
// Some Design code..
#region render
Device.BeginInvokeOnMainThread(() =>
{
scroll = new ScrollView
{
Content = layout
};
TransactionElements.Children.Add(scroll);
#endregion
});
IsBusy = false;
}

Related

Pass-through TextChanged Bindableproperty from a custom Entry control to the actual Entry

I have a custom control, which is basically a XML wrapper around another custom control, with its own CustomRenderer.
Custom Control, basically a Wrapper XAML for another custom control
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.Controls.TitleAndEntry"
xmlns:renderers="clr-namespace:Test.Renderers">
<StackLayout>
<Label
FontAttributes="Bold"
Style="{StaticResource TitleSemiBoldBlackLabel}"/>
<renderers:EntryBottomLine
x:Name="myEntry"
PlaceholderColor="{StaticResource PrimarySolidGrayColor}"
IsPassword="False"
TextColor="{StaticResource BlackColor}"/>
</StackLayout>
</ContentView>
Custom Control Wrapper Code-Behind
public partial class TitleAndEntry : ContentView
{
public TitleAndEntry()
{
InitializeComponent();
}
// Other BindableProperties & code
public static BindableProperty TextEntryChangedProperty = BindableProperty.Create(
nameof(TextEntryChanged), typeof(EventHandler<TextChangedEventArgs>), typeof(TitleAndEntry), null,
propertyChanged: OnTextEntryChanged);
public EventHandler<TextChangedEventArgs> TextEntryChanged
{
get
{
return (EventHandler<TextChangedEventArgs>)GetValue(TextEntryChangedProperty);
}
set
{
SetValue(TextEntryChangedProperty, value);
}
}
private static void OnTextEntryChanged(BindableObject bindable, object oldVal, object newVal)
{
var titleAndEntry = (TitleAndEntry)bindable;
titleAndEntry.myEntry.TextChanged += (EventHandler<TextChangedEventArgs>)newVal;
}
}
}
XAML on the page where I use the custom control
<ctrl:TitleAndEntry
x:Name="user"
Margin="{StaticResource NormalTopPadding}"
TextLabel="{x:Static local:AppResources.User}"
TextChanged="OnMyTextChanged"/>
Code-behind of that page
private void OnMyTextChanged(object sender, TextChangedEventArgs e)
{
// Call to Viewmodel
}
I get this error:
Xamarin Forms No property, bindable property, or event found for 'TextChanged', or mismatching type between value and property
I tried many suggestions, but I cannot get it to work.
I'll answer it myself:
After going back to the InputView (which is the base class for Entry), I noticed that TextChanged is not a BindableProperty, but an event.
public event EventHandler<TextChangedEventArgs> TextChanged;
So I removed the entire BindableProperty and replaced it with:
// On the regular Text propert, call the event handler from the PropertyChanged param
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(TitleAndEntry),
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) => ((TitleAndEntry)bindable).OnTextChanged((TitleAndEntry)bindable, (string)oldValue, (string)newValue));
public event EventHandler<TextChangedEventArgs> TextChanged;
// Simply Invoke the event with the provided args
private void OnTextChanged(TitleAndEntry bindable, string oldValue, string newValue)
{
this.TextChanged?.Invoke(bindable, new TextChangedEventArgs(oldValue, newValue));
}
Now it works as it should.

Xamarin forms turns dark and appshell doesn't work anymore when switching language

I implemented language changing trough AppResources.resx files, I have 2 of these: AppResources.resx and AppResources.fr.resx. Switching the language with the following code:
private void Language_switch(object sender, EventArgs e)
{
var lang_switch = Lang.Text;
if (lang_switch == "FR")
{
CultureInfo language = new CultureInfo("fr");
Thread.CurrentThread.CurrentUICulture = language;
AppResources.Culture = language;
}
else
{
CultureInfo language = new CultureInfo("");
Thread.CurrentThread.CurrentUICulture = language;
AppResources.Culture = language;
}
Application.Current.MainPage = new NavigationPage(new PointsPage());
}
The language switches fine but whenever I do, the app turns dark and the AppShell seems to break, it only shows the top bar with toolbar items i made (in what seems to be the standard xamarin color) and showing what seems to be it trying to show the navigation at the bottom, but this only looks like a bar but doesn't seem to have navigation on it and doesn't have any of the labels for navigation.
The content on the page also seems to overlap with this bar going over it if I scroll down. If I press the switch button again it does still switch languages but stay in this dark mode. I don't have any of the dark color set in my app and don't have a dark mode implemented.
It also seems to be doing this on every single page I do it on. How can i stop this from happening so it uses the layout i have made for my app and doesn't turn dark?
Edit: I found out that problem isn't in the language switch. When I go to another page just using
Application.Current.MainPage = new NavigationPage(new PointsPage());
and removing the the language switch code it still does the weird thing where it changes colors. From what it looks like to me is that the page gets put on top without the AppShell moving to be on top of that. Is there a way to reload the AppShell?
Edit2: I managed to fix it. As I suspected the AppShell wasn't reloading and wasn't being put on top of the reloaded page. I added
Application.Current.MainPage = new AppShell();
underneath the page reload and now everything is working
When you use the .resx file to make the localization, create the resx file with the matched file name, when you change the system language, reopen the app would show the matched resource your set in .resx.
For more details about it, you could refer to the MS docs. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/text?pivots=windows
Code sample: https://github.com/xamarin/xamarin-forms-samples/tree/main/UsingResxLocalization
If you want to change it at runtime, you could use ResourceManager. It provides convenient access to culture-specific resources at runtime.
I make a simple example for your reference.
MainPage: String1, Settings are the key in .resx file.
<StackLayout>
<Label Text="{Binding Resources[String1]}"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Button Text="{Binding Resources[Settings]}"
HorizontalOptions="Center"
Clicked="Button_Clicked" />
</StackLayout>
Code behind:
public MainPage()
{
InitializeComponent();
this.BindingContext = new MainPageViewModel();
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new SettingsPage());
}
SettingsPage:
<StackLayout>
<Label Text="{Binding Resources[PickLng]}" />
<Picker ItemsSource="{Binding Languages}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}" />
</StackLayout>
Code behind:
public SettingsPage()
{
InitializeComponent();
BindingContext = new SettingsViewModel();
}
ViewModel:
public class CultureChangedMessage
{
public CultureInfo NewCultureInfo { get; private set; }
public CultureChangedMessage(string lngName)
: this(new CultureInfo(lngName))
{ }
public CultureChangedMessage(CultureInfo newCultureInfo)
{
NewCultureInfo = newCultureInfo;
}
}
public class LocalizedResources : INotifyPropertyChanged
{
const string DEFAULT_LANGUAGE = "en";
readonly ResourceManager ResourceManager;
CultureInfo CurrentCultureInfo;
public string this[string key]
{
get
{
return ResourceManager.GetString(key, CurrentCultureInfo);
}
}
public LocalizedResources(Type resource, string language = null)
: this(resource, new CultureInfo(language ?? DEFAULT_LANGUAGE))
{ }
public LocalizedResources(Type resource, CultureInfo cultureInfo)
{
CurrentCultureInfo = cultureInfo;
ResourceManager = new ResourceManager(resource);
MessagingCenter.Subscribe<object, CultureChangedMessage>(this,
string.Empty, OnCultureChanged);
}
private void OnCultureChanged(object s, CultureChangedMessage ccm)
{
CurrentCultureInfo = ccm.NewCultureInfo;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item"));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class ViewModelBase : INotifyPropertyChanged
{
public LocalizedResources Resources
{
get;
private set;
}
public ViewModelBase()
{
Resources = new LocalizedResources(typeof(AppResources), App.CurrentLanguage);
}
public void OnPropertyChanged([CallerMemberName] string property = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainPageViewModel : ViewModelBase
{ }
public class SettingsViewModel : ViewModelBase
{
public List<string> Languages { get; set; } = new List<string>()
{
"EN",
"FR"
};
private string _SelectedLanguage;
public string SelectedLanguage
{
get { return _SelectedLanguage; }
set
{
_SelectedLanguage = value;
SetLanguage();
}
}
public SettingsViewModel()
{
_SelectedLanguage = App.CurrentLanguage;
}
private void SetLanguage()
{
App.CurrentLanguage = SelectedLanguage;
MessagingCenter.Send<object, CultureChangedMessage>(this,
string.Empty, new CultureChangedMessage(SelectedLanguage));
}
}

Xamarin forms - How do I set font for toolbaritems

I have a toolbar in my mainpage and would like to set the font for each toolbaritem (so I can set custom fonts or normal fonts). So far I have been trying to get this done by implementing my own effect and this code works for labels but not for toolbaritems.
Whenever I run this code the effects gets added to the toolbaritem, but the effect code in android doesn't get called.
Does anyone know why I am unable to set fonts for toolbaritems with effects?
GitHub: https://github.com/jashan07/CustomEffectTest
Edit:
Brad Dixon suggested using TitleView which allows me to place labels in my navigationbar. As mentioned before the effect works for every control except toolbaritems.
This is a workaround which works for now (don't know about the limits or effects this will have) but I am still wondering why this isn't working for toolbaritems.
(TitleView was introduced in Xamarin.Forms V3.2)
My effect class:
public static class ChangeFontEffect
{
public static readonly BindableProperty FontProperty = BindableProperty.CreateAttached("Font",
typeof(string),
typeof(ChangeToolbarFontEffect),
null, propertyChanged: OnFontChanged);
private static void OnFontChanged(BindableObject bindable, object oldValue, object newValue)
{
if(bindable is Label labelControl)
{
if (!labelControl.Effects.Any((e) => e is ChangeToolbarFontEffect))
labelControl.Effects.Add(new ChangeToolbarFontEffect());
}
else if(bindable is ToolbarItem toolbarItem)
{
if (bindable is ToolbarItem)
if (!toolbarItem.Effects.Any((e) => e is ChangeToolbarFontEffect))
toolbarItem.Effects.Add(new ChangeToolbarFontEffect());
}
return;
}
public static string GetFont(BindableObject view)
{
return (string)view.GetValue(FontProperty);
}
public static void SetFont(BindableObject view, string value)
{
view.SetValue(FontProperty, value);
}
class ChangeToolbarFontEffect : RoutingEffect
{
public ChangeToolbarFontEffect() : base("CustomEffectTest.ChangeToolbarFontEffect") { }
}
}
XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:effects="clr-namespace:CustomEffectTest.Effects"
x:Class="CustomEffectTest.MainPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="normal text"></ToolbarItem>
<ToolbarItem Text="ﭗ" effects:ChangeFontEffect.Font="materialdesignicons-webfont.ttf"></ToolbarItem>
</ContentPage.ToolbarItems>
Android
[assembly: ResolutionGroupName("bottomNavTest")]
[assembly: ExportEffect(typeof(ChangeToolbarFontEffect), "ChangeToolbarFontEffect")]
namespace bottomNavTest.Droid
{
public class ChangeToolbarFontEffect : PlatformEffect
{
TextView control;
protected override void OnAttached()
{
try
{
control = Control as TextView;
Typeface font = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, ChangeFontEffect.GetTextFont(Element));
control.Typeface = font;
}
catch(Exception e)
{
}
}
protected override void OnDetached()
{
}
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{
if (args.PropertyName == ChangeFontEffect.TextFontProperty.PropertyName)
{
var val = ChangeFontEffect.GetTextFont(Element);
if (val != null)
{
Typeface font = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, ChangeFontEffect.GetTextFont(Element));
control.Typeface = font;
}
}
}
}
}

access and open DisplayActionSheet from view model

i have a toolbar in my content page where there is one item called add , on clicking over add i want to open DisplayActionSheet
i have created ContentPage Toolbar in xaml and attached ICommand to it in view model. Now DisplayActionSheet is accessible only in View hence i am not sure how will i able to access it and render it from view model.
xaml file
<ContentPage.ToolbarItems>
<ToolbarItem Name="" Icon="ic_add.png" Order="Primary" Priority="0" Command="{Binding OnAddContactCommand}"/>
<ToolbarItem Name="" Icon="ic_search.png" Order="Primary" Priority="1" Command="{Binding OnContactSearchCommand}" />
</ContentPage.ToolbarItems>
View model
public ICommand OnContactSearchCommand => new Command(OnContactSearch);
public ICommand OnAddContactCommand => new Command(OnAddContactSearch);
events
private async void OnAddContactSearch()
{
//var action = await DisplayActionSheet(AppResources.select_contact_source, AppResources.cancel, null, AppResources.manual, AppResources.phonebook);
}
private void OnContactSearch()
{
Debug.WriteLine("OnContactSearch");
}
Like #Alessandro said Application.Current.MainPage works fine for action sheets and alerts as well. To hide view specific stuff from view model I created an IMessageBoxService which is injected into the view models' contructors that need it. Note that I am using the Autofac IoC container. For Xamarin's DependencyService you have change the constructors and look up the service in code.
IMessageBoxService.cs
public interface IMessageBoxService
{
void ShowAlert(string title, string message, Action onClosed = null);
// ...
Task<string> ShowActionSheet(string title, string cancel, string destruction, string[] buttons = null);
}
MessageBoxService.cs
public class MessageBoxService : IMessageBoxService
{
private static Page CurrentMainPage { get { return Application.Current.MainPage; } }
public async void ShowAlert(string title, string message, Action onClosed = null)
{
await CurrentMainPage.DisplayAlert(title, message, TextResources.ButtonOK);
onClosed?.Invoke();
}
public async Task<string> ShowActionSheet(string title, string cancel, string destruction = null, string[] buttons = null)
{
var displayButtons = buttons ?? new string[] { };
var action = await CurrentMainPage.DisplayActionSheet(title, cancel, destruction, displayButtons);
return action;
}
}
AppSetup.cs
protected void RegisterDependencies(ContainerBuilder cb)
{
// ...
cb.RegisterType<MessageBoxService>().As<IMessageBoxService>().SingleInstance();
}
Usage
public class EditProductViewModel : AddProductViewModel
{
private IMessageBoxService _messageBoxService;
public ICommand DeleteCommand { get; set; }
public EditProductViewModel(IPageNavigator navigator, IMessenger messenger,
IMessageBoxService messageBoxService, TagDataStore tagDataStore) : base(navigator, messenger, tagDataStore)
{
_messageBoxService = messageBoxService;
DeleteCommand = new Command(DeleteItem);
}
...
private async void DeleteItem()
{
var action = await _messageBoxService.ShowActionSheet(TextResources.MenuTitleDeleteProduct,
TextResources.ButtonCancel, TextResources.ButtonDelete);
if (action == TextResources.ButtonDelete)
{ } // delete
If you are doing viewmodel first navigation (s. Xamarin or Jonathan Yates' blog) you may chose to make this part of the Navigator service. It's a matter of taste
try with
Application.Current.MainPage.DisplayActionSheet();

Xamarin.Forms PCL MVVM Light > Custom Control > Best Practice?

Hy
I would like to share my approach for a custom xamarin.forms control within a Xamarin PCL Project with MVVM-Light. What do you think about it?
Custom Control -> PersonPanel.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="xxx.PersonPanel">
<StackLayout Orientation="Vertical">
<Label x:Name="titleLabel" Text="{Binding TitleLabel}"/>
<Entry x:Name="filterText" Placeholder="{Binding FilterPlaceholderText}" Text="{Binding Filter.Lookup}" TextChanged="OnFilterTextChanged"/>
<Label x:Name="resultText" Text="{Binding ResultText}" IsVisible="{Binding ResultTextVisible}"/>
</StackLayout>
</ContentView>
Code-Behind -> PersonPanel.xaml.cs:
public partial class PersonPanel : ContentView
{
public PersonPanel()
{
InitializeComponent();
//Init ViewModel
BindingContext = ServiceLocator.Current.GetInstance<PersonPanelViewModel>();
}
private PersonPanelViewModel PersonPanelViewModel
{
get
{
return (PersonPanelViewModel)BindingContext;
}
}
public string TitleLabel
{
get
{
return PersonPanelViewModel.TitleLabel;
}
set
{
PersonPanelViewModel.TitleLabel = value;
}
}
public string FilterPlaceholderText
{
get
{
return PersonPanelViewModel.FilterPlaceholderText;
}
set
{
PersonPanelViewModel.FilterPlaceholderText = value;
}
}
private void OnFilterTextChanged(object sender, EventArgs e)
{
PersonPanelViewModel.SearchCommand.Execute(null);
}
}
ViewModel -> PersonPanelViewModel:
public class PersonPanelViewModel : ViewModelBase
{
private IPersonService _personService;
private decimal _personId = 0;
private string _titleLabel = string.Empty;
private string _filterPlaceholderText = string.Empty;
private string _resultText = string.Empty;
private bool _resultTextVisible = true;
public PersonPanelViewModel(IPersonService personService)
{
_personService = personService;
// Init Filter
Filter = new PersonFilter();
// Init Commands
SearchCommand = new RelayCommand(Search);
}
public ICommand SearchCommand { get; set; }
public PersonFilter Filter
{
get;
private set;
}
public string ResultText
{
get
{
return _resultText;
}
set
{
Set(() => ResultText, ref _resultText, value);
}
}
public bool ResultTextVisible
{
get
{
return _resultTextVisible;
}
set
{
Set(() => ResultTextVisible, ref _resultTextVisible, value);
}
}
public string FilterPlaceholderText
{
get
{
return _filterPlaceholderText;
}
set
{
Set(() => FilterPlaceholderText, ref _filterPlaceholderText, value);
}
}
public string TitleLabel
{
get
{
return _titleLabel;
}
set
{
Set(() => TitleLabel, ref _titleLabel, value);
}
}
public decimal PersonId
{
get
{
return _PersonId;
}
set
{
Set(() => PersonId, ref _PersonId, value);
}
}
private async void Search()
{
//Reset
ResultText = string.Empty;
ResultTextVisible = false;
PersonId = 0;
if (Filter.PersonLookup != null && Filter.PersonLookup.Length >= 3)
{
//Call to Person Service
List<PersonResult> Person = await _personService.FindpersonByFilter(Filter);
if (Person.Count == 1)
{
PersonId = Person[0].PersonId;
ResultText = Person[0].PersonName;
ResultTextVisible = true;
}
}
}
}
Using of Control in another View:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:components="clr-namespace:xxx.ViewElements.Components"
x:Class="xxx.MainPage">
<StackLayout Orientation="Vertical">
<components:PersonPanel x:Name="personPanel" TitleLabel="Person" FilterPlaceholderText="Type your search criteria here..."/>
</StackLayout>
</ContentPage>
I'm using Autofac as the IOC Container.
What do you think about it? I am using MVVM the right way (it's very new to me)?
Is there a better way to deal with calling the Command from the Event (TextChanged) on the view?
What's about the properties in the Code-Behind (which do a routing to the ViewModel)?
Edit:
I'll try to describe, what I want to achieve:
Creating our own control (reusable in different views, cross-platform) -> PersonPanel.xaml
Written in XAML in our PCL Project with pure Xamarin.Forms controls in it
The control should have it's own commands (Search) and properties
One of the commands is using a Service
The control should get the Service (as an Interface) injected through IOC
The Service itself is also implemented in the PCL Project and makes a REST Call to a Webservice
The Result of the Call is than set to a property of the control -> ResultText Property
The Result is visible to the User
-> With the above implementation, all of that works, but I'm not sure if this is the right way...
Thanks for your help!
Kind regards,
Peter
The approach for mapping the event to the command is exactly as I would perform.
The rest is a little bit confusing. The general pattern is to create bindable properties in your control that are exposed to the view model when instantiated within the host view. A very basic sample structure is below:
public class TestLabelControl : Label
{
public static readonly BindableProperty TestTitleProperty = BindableProperty.Create< TestLabelControl, string> (p => p.TestTitle, null);
public string TestTitle {
get {
return (object)GetValue (TestTitleProperty);
}
set {
SetValue (TestTitleProperty, value);
}
}
}
public class TestContentPage : ContentPage
{
public TestContentPage()
{
var testLabel = new TestLabel();
testLabel.SetBinding<TestContentPageViewModel>(TestLabel.TestTitleProperty, vm => vm.TestLabelTitle, BindingMode.Default);
Content = testLabel;
}
}
public class TestContentPageViewModel
{
public string TestLabelTitle{get;set;}
public TestContentPageViewModel()
{
TestLabelTitle = "Something random";
}
}
You would then create the native renderers to handle the drawing on each platform.
By following this approach you keep the code separated and concise. It does seem a slightly long winded way of getting things done but it is highly scalable and configurable.

Resources