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.
Related
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;
In my XAML I define the binding context like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
xmlns:template="clr-namespace:Japanese.Templates"
xmlns:viewModels="clr-namespace:Japanese.ViewModels; assembly=Japanese"
x:Class="Japanese.Cards" Title="{Binding Title}">
<ContentPage.BindingContext>
<viewModels:CardsViewModel />
</ContentPage.BindingContext>
</ContentPage>
What I would like to know is how can I access this context in my C# back end.
public partial class Cards : ContentPage
{
public Cards()
{
InitializeComponent();
NavigationPage.SetBackButtonTitle(this, "Back");
}
protected override void OnAppearing()
{
// I want to set some properties of the view here
It seems you cannot give it an x:Name attribute like other elements in your XAML. In that case, your options are limited to declaring the object for your binding context in the code-behind, or referencing it from the BindingContext property.
For the latter approach, do it like this:
protected override void OnAppearing()
{
var cardsViewModel = BindingContext as CardsViewModel;
if (cardsViewModel == null)
return;
cardsViewModel.Property = Value;
}
Earlier answer for reference:
You should be able to give it a name like so:
<ContentPage.BindingContext>
<viewModels:CardsViewModel x:Name="cardsViewModel" />
</ContentPage.BindingContext>
This will effectively just create a declaration like this in generated code:
private CardsViewModel cardsViewModel;
You can now access it in your code-behind:
protected override void OnAppearing()
{
cardsViewModel.Property = Value;
}
I have Template1 that inherits from ContentView. For the purpose of this question I removed a lot of things in the template to make it simple.
<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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.Template1" x:Name="this">
<Label Grid.Column="0" Text="{Binding Text, Source={x:Reference this}}" />
</ContentView>
and the Template1 C# back end
namespace Japanese
{
public partial class Template1 : ContentView
{
public CardOrderTemplate()
{
InitializeComponent();
}
}
}
I would like this template to share bindings in this class and so I tried some different ways to do this but none seem to work. Here's what I was trying. Not sure but I guess I need something like a ViewModel for the template but I am not sure how I could go about implementing this.
namespace Japanese
{
public class SegBase : ContentView
{
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(SegTemplate), default(string));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
}
Does anyone know how I can do this? I tried making the Template1 class inherit from SegBase but it gives me an error because the XAML is a type ContentView and the C# is not inheriting from ContentView.
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>
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>().