Xamarin Forms: Prism -- Issue with using unity IoC? - xamarin

In my xamarin forms app using Prism MVVM Framework, How should I use IoC containers?
There are no
Container.Resolve<Interface,Implentation>
I think we need to resolve the IoC and initialize in app.xaml.cs. But I am not able to find proper way to do it.
Can anyone help me out ?
UPDATE:
PAGE:
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="CoC.Core.Views.MenuPage">
<ContentPage.Content>
<ListView x:Name="info"
SeparatorVisibility="None"
SeparatorColor="Transparent"
HasUnevenRows="false"
RowHeight="50" BackgroundColor="#485366" >
<ListView.ItemTemplate>
<DataTemplate>
<!--<ImageCell Text="{Binding Title}" ImageSource="{Binding IconSource}" /> -->
<ViewCell>
<!--<Label Text="{Binding Title}" />-->
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
ViewModel:
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using Prism.Navigation;
namespace CoC.Core.ViewModels
{
public class MenuPageViewModel : BindableBase , INavigationAware
{
IMenuList _menuList;
public ObservableCollection<MenuItem> ConductList { get; set; }
public void OnNavigatedFrom(NavigationParameters parameters)
{
//throw new NotImplementedException();
}
public void OnNavigatedTo(NavigationParameters parameters)
{
//throw new NotImplementedException();
}
public MenuPageViewModel(IMenuList MenuList)
{
_menuList = MenuList;
ConductList = _menuList.GetMenuList();
}
}
}
APP:
using Prism.Unity;
using CoC.Core.Views;
namespace CoC.Core
{
public partial class App : PrismApplication
{
protected override void OnInitialized()
{
InitializeComponent();
//NavigationService.NavigateAsync("MainPage?title=Hello%20from%20Xamarin.Forms");
NavigationService.NavigateAsync("MenuPage");
}
protected override void RegisterTypes()
{
Container.RegisterTypeForNavigation<MainPage>();
Container.RegisterTypeForNavigation<RootPage>();
Container.RegisterTypeForNavigation<MenuPage>();
}
}
}
When I run this code, I am getting error in Main.cs of IOS pro
Error:
Foundation.MonoTouchException
NSInternalLnconistencyException Reason: Application window are expected to have a root view controller at the end of the application.

What you are looking for is an extension method in Unity. You need to add the using Microsoft.Practices.Unity namespace to your code file. The you can register your services using Container.Register<IService,MyService>().

Related

Xamarin Forms and PropertyChanged.Fody not updating UI

I have a Xamarin Forms project using MVVM in which I am attempting to use Fody and the PropertyChanged.Fody package. No matter what I try it simply does not work. I have spent the day searching for examples of projects using PropertyChanged.Fody and can't find any example sample code that actually works. Can someone help me out? Thanks.
I have added both Fody and PropertyChanged.Fody nugets to the project.
I have added the FodyWeavers.xml file to the Forms project which looks like...
<?xml version="1.0" encoding="utf-8"?>
<Weavers>
<PropertyChanged />
</Weavers>
My view is a standard ContentPage...
<ContentPage.BindingContext>
<viewmodels:GetStartedViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout >
<Entry Text="{Binding TestMessage}" TextColor="Lime" FontSize="20" />
</StackLayout>
</ContentPage.Content>
I have tried implementing PropertyChanged.Fody on the ViewModel in 2 ways, both of which fail to work.
1)
public class GetStartedViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string TestMessage { get; set; }
}
2)
[AddINotifyPropertyChangedInterface]
public class GetStartedViewModel
{
public string TestMessage { get; set; }
}

Using method from App class in separate form xamarin

I am a beginner, so this should be an easy fix for someone with experience.
I am a veterinarian trying to build an app for vets to use. I am trying to learn via youtube and previous posts online, but I cannot find a solution for my roadblock:
I am trying to call a method already written in the App class:
Settings form binds a volume of onhand penicillin.
Usage form displays that volume, and asks the user to enter a volume used.
On button click I need the onhand volume to be 'updated' but i can't call the method in the App class (which has a get and set)
I have simplified for easier evaluation:
App code behind:
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace methods
{
public partial class App : Application
{
private const string penicillin = "penicillin";
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
public string Penicillin
{
get
{
if (Properties.ContainsKey(penicillin))
{
return Properties[penicillin].ToString();
}
return "";
}
set
{
Properties[penicillin] = value;
}
}
}
}
Settings Form:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="methods.Settings">
<ContentPage.Content>
<StackLayout>
<Label Text="Penicillin Onhand" ></Label>
<Entry Text="{Binding Penicillin}" Keyboard="Numeric" ></Entry>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Settings Code behind:
using Xamarin.Forms;
namespace methods
{
public partial class Settings : ContentPage
{
public Settings()
{
InitializeComponent();
BindingContext = Application.Current;
}
}
}
Usage form:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="methods.Usage">
<ContentPage.Content>
<StackLayout>
<Label Text="Penicillin Held" ></Label>
<Label x:Name="Held" Text="{Binding Penicillin}" ></Label>
<Label Text="Penicillin Used" ></Label>
<Entry x:Name="Using" Placeholder="ml" Keyboard="Numeric" ></Entry>
<Button Text="Use" Clicked="Used_Clicked"></Button>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Usage Code behind:
using Xamarin.Forms;
namespace methods
{
public partial class Usage : ContentPage
{
public Usage()
{
InitializeComponent();
BindingContext = Application.Current;
}
void Used_Clicked(object sender, System.EventArgs e)
{
var VUsed = double.Parse(Using.Text);
var VHeld = double.Parse(Held.Text);
var Remaining = VHeld - VUsed;
//how do i code the following? Error:'App' does not contain definition for Penicillin????
App.Penicillin.value = Remaining;
}
}
}
You don't need to create a new instance of App - Xamarin Forms already maintains a reference to the current instance
((App)Application.Current).Penicillin = Remaining;

How can I make a template call a method?

I have this template:
<?xml version="1.0" encoding="utf-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Japanese.OpenPageTemplate"
x:Name="this">
<Label Text="ABC" VerticalTextAlignment="Center" />
</ViewCell>
and the code behind:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Japanese.Templates
{
public partial class OpenPageTemplate : ViewCell
{
public OpenPageViewCellTemplate()
{
InitializeComponent();
}
protected override void OnTapped()
{
base.OnTapped();
// I need to call openPage() here or at least have openPage() called from the place where the template is used.
}
}
}
Can someone tell me how I can make this template call a method called openPage() when the user taps on the ViewCell? In a previous question there was an answer about using the .Invoke method that went something like this:
ClickAction?.Invoke(this, new EventArgs());
However this time there's just one action to invoke and I don't need to pass information on the action into ClickAction.
Wrap the ViewCell in a DataTemplate:
<?xml version="1.0" encoding="utf-8" ?>
<DataTemplate xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:template="clr-namespace:Japanese"
x:Class="Japanese.OpenPageTemplate">
<ViewCell Tapped="OnOpenPageTapped">
...
</ViewCell>
</DataTemplate>
Codebehind:
namespace Japanese
{
public partial class OpenPageTemplate : DataTemplate
{
public OpenPageTemplate ()
{
InitializeComponent ();
}
private void OnOpenPageTapped(object sender, EventArgs e)
{
//example: template is an itemtemplate for a list of class A.B with property C
var c = ((sender as ViewCell)?.BindingContext as A.B)?.C;
}
...
Subscribe to the desired Cell.Tapped Event and invoke the action when the event is raised.
XAML
<template:OpenPageTemplate Tapped="OnOpenPageTapped" />
Code behind
private void OnOpenPageTapped(object sender, EventArgs args) {
openPage();
}
assuming that openPage() is accessible from the place where the template is used.

New Bindable Picker can't set default item from viewmodel

Trying to get the new bindable picker to work in Xamarin Forms version 2.3.4.270 with Visual Studio 2017.
I can get the view to load in a list from the view model so when you click the picker, it does show the list of items. I want to set a default item in the picker on screen load though and nothing I have tried is working.
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:local="clr-namespace:BindablePickerTest"
x:Class="BindablePickerTest.MainPage">
<StackLayout>
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Picker Title="Test Picker" ItemsSource="{Binding Names}" SelectedItem="{Binding Name, Mode=TwoWay}" />
</StackLayout>
</ContentPage>
View Code Behind: (the view model is in the code behind for simplicity)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace BindablePickerTest
{
public partial class MainPage : ContentPage
{
MainPageViewModel vm;
public MainPage()
{
InitializeComponent();
this.BindingContext = vm = new MainPageViewModel();
}
}
public class MainPageViewModel : INotifyPropertyChanged
{
List<string> names = new List<string>
{
"Doug",
"Fred",
"Steve",
"Tom",
"Victor"
};
public List<string> Names => names;
public string Name = "Steve";
public event PropertyChangedEventHandler PropertyChanged;
}
}
When this runs, the picker is still empty - "Steve" is not selected. When clicking the picker, the list shows correctly and I can choose any name, but it will not set a default selection.
Any help is appreciated!
Name is a field right now. For Binding to work - it needs to be converted to property.
public string Name => "Steve";

Can I use a rightSwipeGestureRecognizer for a content page?

I have an application that I am looking at. Currently it has this:
C# code
namespace Japanese
{
public partial class PhrasesPage : ContentPage
public PhrasesFrame phrasesFrame = new PhrasesFrame();
public PhrasesPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
phrasesStackLayout.Children.Add(phrasesFrame);
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:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.PhrasesPage"
x:Name="PhraseContentPage">
<ContentPage.Content>
<StackLayout x:Name="phrasesStackLayout">
</StackLayout>
</ContentPage.Content>
</ContentPage>
And then inside of that:
C# code
namespace Japanese
{
public partial class PhrasesFrame : Frame
XAML
<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Japanese.PhrasesFrame" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Transparent" Padding="0" HasShadow="false">
<StackLayout x:Name="phrasesFrameStackLayout" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
There's a custom renderer for the frame that implements rightSwipeGestureRecognizer
[assembly: ExportRenderer(typeof(PhrasesFrame), typeof(PhrasesFrameCustomRenderer))]
namespace Japanese.iOS
{
public class PhrasesFrameCustomRenderer : FrameRenderer
{
UISwipeGestureRecognizer leftSwipeGestureRecognizer;
UISwipeGestureRecognizer rightSwipeGestureRecognizer;
PhrasesFrame frame;
bool rightSwipeEnabled = false;
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
frame = Element as PhrasesFrame;
rightSwipeGestureRecognizer = new UISwipeGestureRecognizer();
rightSwipeGestureRecognizer.Direction = UISwipeGestureRecognizerDirection.Right;
rightSwipeGestureRecognizer.NumberOfTouchesRequired = 1;
rightSwipeGestureRecognizer.AddTarget((obj) =>
{ });
My question is, do I need to have a frame inside of the content page to implement a SwipeGestureRecognizer?
I think your code could also work on any given other element. Since you're currently inheriting the CustomRenderer from FrameRenderer it will only work on Frame objects and more specifically PhrasesFrame objects (as defined in the ExportRenderer attribute. You can easily change this to e.g. PageRenderer like such:
[assembly: ExportRenderer(typeof(MyContentPage), typeof(ContentPageRenderer))]
namespace Japanese.iOS
{
public class ContentPageRenderer : PageRenderer
{
You could then change every piece of code referencing the Frame in this renderer to reference to ContentPage instead and it will probably work. That does mean that every ContentPage object gets this functionality, so you will most likely have to create your own object inheriting from ContentPage and apply the CustomRenderer to that.
public class MyContentPage : ContentPage
{
}
And update your XAML accordingly:
<?xml version="1.0" encoding="UTF-8"?>
<local:MyContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.PhrasesPage"
x:Name="PhraseContentPage">
<ContentPage.Content>
<StackLayout x:Name="phrasesStackLayout">
</StackLayout>
</ContentPage.Content>
</local:MyContentPage>

Resources