MasterDetail Page debugging error: CS0263 - xaml

I defined a basic master detail page.But whenever I try to start emulator, I am getting this error:
"CS0263 Partial declarations of 'MainPage' must not specify different base classes"
Its been 1 week and still couldnt solve it. I know it is about inheritance but what should I do ? Any ideas?
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MasterDetail.MainPage">
<MasterDetailPage.Master>
<ContentPage BackgroundColor="White" Title="Master">
<StackLayout >
<StackLayout>
<Frame BackgroundColor="#48b6a6" >
<Image Source="heartbeatt.png" HorizontalOptions="Center"
VerticalOptions="Center"/>
</Frame>
</StackLayout>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<ContentPage>
<StackLayout>
<Label Text="Detail"></Label>
</StackLayout>
</ContentPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
cs file here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace MasterDetail
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
}
}

this is the problem
public partial class MainPage : ContentPage
in the XAML MainPage is a MasterDetailPage, not a ContentPage. Do this instead
public partial class MainPage : MasterDetailPage
this is exactly what the error message is telling you: "must not specify different base classes"

Related

Xamarin forms Add button in TabbedPage

I have a question. I created the following TabbedPage:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:MyApp.Views"
mc:Ignorable="d"
x:Class="MyApp.Views.MainPage"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
BarBackgroundColor="White"
BarTextColor="Black"
android:TabbedPage.BarItemColor="#B2B2B2"
android:TabbedPage.BarSelectedItemColor="#56D7A5"
android:TabbedPage.IsSwipePagingEnabled="False">
<TabbedPage.Children>
<NavigationPage Title="page1" IconImageSource="navbar_page1">
<x:Arguments>
<views:page1 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="page2" IconImageSource="navbar_page2">
<x:Arguments>
<views:page2 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="page3" IconImageSource="navbar_page3">
<x:Arguments>
<views:page3 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
</TabbedPage>
Now on every page I have added this custom FabMenu like this:
<c:FloatingMenu Margin="0, 0, 10, 10" BGColor="#56D7A5" OpenIcon="openFab_icon" CloseIcon="closeFab_icon"
AbsoluteLayout.LayoutBounds=".95,.95" AbsoluteLayout.LayoutFlags="PositionProportional">
<c:FloatingButton x:Name="btnAddHomework" BGColor="#59E1FF" IconSrc="add_homework_icon" OnClickCommand="{Binding btnAddHomeworkCommand}" />
<c:FloatingButton x:Name="btnAddDeadline" BGColor="#0FF1A0" IconSrc="add_deadline_icon"/>
<c:FloatingButton x:Name="btnAddTest" BGColor="#5988FF" IconSrc="add_test_icon"/>
</c:FloatingMenu>
The problem is that every page has his own FabMenu, so you see it dissapear and reappear on every page, so my question is: Is there some kind of root view that overlays all the tabs in the TabbedPage?
Please let me know how I do that!
Disclaimer
I came up with a way to create the effect wanted using only pure Xamarin.Forms. Read along and pay attention to the tricky parts of the solution.
Abstract
This solution is achieved implementing AbsoluteLayout, CarouselView, IndicatorView and DataTemplateSelector. Xamarin.Forms 4.8 is supposed in what follows. If a lower version is used, please take into account that features like CarouselView or IndicatorView could be in Preview status.
DataTemplateSelector, CarouselView and IndicatorView are used to simulate a TabbedPage, and AbsoluteLayout is used to provide the Overlay.
So, now with the solution:
Create your Views
Here you create a view for each of the pages you want. In this example i want my application to consist of two pages, so i create two views (code behind remains untouched):
View1.xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="overlayTest.View1"
BackgroundColor="Black">
<ContentView.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms 1!"
TextColor="White"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
View2.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="overlayTest.View2">
<ContentView.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms 2!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
Create a DataTemplateSelector
This will be used by the CarouselView in order to select one view or the other depending on the current Position.
using System;
using Xamarin.Forms;
namespace overlayTest
{
class MyTemplateSelector : DataTemplateSelector
{
readonly DataTemplate view1, view2;
public MyTemplateSelector()
{
view1 = new DataTemplate(typeof(View1));
view2 = new DataTemplate(typeof(View2));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
String s = item.ToString();
if(s == "1")
{
return view1;
}
return view2;
}
}
}
Create your Main Page
Page1.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:t="clr-namespace:overlayTest"
x:Class="overlayTest.Page1">
<ContentPage.Resources>
<ResourceDictionary>
<t:MyTemplateSelector x:Key="templateSelector"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<AbsoluteLayout>
<StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Padding="0"
Spacing="0">
<CarouselView ItemTemplate="{StaticResource templateSelector}"
IndicatorView="indicatorView">
<CarouselView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>1</x:String>
<x:String>2</x:String>
</x:Array>
</CarouselView.ItemsSource>
</CarouselView>
<IndicatorView x:Name="indicatorView">
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand">
<Frame Margin="10">
<Label/>
</Frame>
</StackLayout>
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>
</StackLayout>
<ContentView
IsVisible="True" VerticalOptions="Start"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Transparent">
<Frame CornerRadius="10"
Margin="20"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand" InputTransparent="False">
<StackLayout Padding="0">
<Label
FontSize="Medium"
TextColor="Black"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="I am floating here"/>
<Switch IsToggled="True" />
</StackLayout>
<Button Text="Save"
BackgroundColor="Accent"/>
</StackLayout>
</Frame>
</ContentView>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
And in the code behind we set the name of the tabs. Here please put attention in the fact that i am supposing an element tree of a StackLayout -> Frame -> Label. If you change the IndicatorTemplate, you will have to also modify this part of the code!
Page1.xaml.cs
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace overlayTest
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
indicatorView.PropertyChanged += (s, a) =>
{
if (a.PropertyName == IndicatorView.HeightProperty.PropertyName)
{
var indicators = indicatorView.IndicatorLayout.Children.ToList();
int counter = 0;
foreach(var indicator in indicators)
{
var indicatorBaseStack = (StackLayout)indicator;
var indicatorFrame = (Frame)indicatorBaseStack.Children[0];
var indicatorFrameLabel = (Label)indicatorFrame.Content;
indicatorFrameLabel.Text = counter == 0 ? "View1" : "View2";
counter++;
}
}
};
}
}
}
Finally set that Page to the MainPage property of App:
public App()
{
InitializeComponent();
MainPage = new Page1();
}
The final result looks like this:
As a workaround, you could set ToolbarItem of each ContentPage (or you can define a base ContentPage).
<ContentPage.ToolbarItems>
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Clicked="{Binding xx}"
Priority="0" />
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Priority="1" />
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Priority="2" />
</ContentPage.ToolbarItems>
I recommend creating a BaseContentPage that includes a static FloatingButton. This allows every page to inherit from BaseContentPage and use the same FloatingButton.
Code
BaseContentPage
abstract class BaseContentPage : ContentPage
{
protected static Button Button { get; } = new Button { Text = $"This button was created at {DateTimeOffset.UtcNow}" }.Invoke(button => button.Clicked += HandleButtonClicked);
static async void HandleButtonClicked(object sender, EventArgs e) =>
await Application.Current.MainPage.DisplayAlert("Button Clicked", "This is the same button on both pages", "OK");
}
Example LabelPage
class LabelPage : BaseButtonPage
{
public LabelPage()
{
Title = "LabelPage";
Content = new StackLayout
{
Children =
{
new Label { Text = "Label Page" }.TextCenter().Center(),
Button
}
}
}
}
Example ButtonPage
class ButtonPage : BaseButtonPage
{
public ButtonPage()
{
Title = "ButtonPage";
Content = Button;
}
}
Example App
public class App : Application
{
public App()
{
Device.SetFlags(new[] { "Markup_Experimental" });
MainPage = new TabbedPage
{
Children =
{
new ButtonPage(),
new LabelPage()
}
};
}
}
Sample App
Here is the sample app used to create the attached GIF:
https://github.com/brminnick/TabbedPageButton/

How to Bind Static Class property to UI component in XAML / Xamarin

In Xamarin application, I am not able to Bind the static property of the C# user defined static Class property (Colors.BackgroundColor) to XAML. I need to set the background of the color of grid by static value defined in static class.
But I am getting the error
Type UserInterfaceDefinitions not found in xmlns
on this XAML
BackgroundColor = "{Binding Source = {x:Static MyNamespace.Mobile:UserInterfaceDefinitions.Colors} }"
Static Class code
namespace MyNamespace.Mobile
{
public static class UserInterfaceDefinitions
{
public static class Colors
{
public static string BackgroundColor = "#DCECE";
}
}
}
XAML Code
<?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:buttons="clr-namespace:MyNamespace.Mobile.UI.Buttons"
xmlns:Status="clr-namespace:MyNamespace.Mobile.UI.StatusDetails"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!-- I am getting the error as Type UserInterfaceDefinitions not found in xmlns-->
<BoxView Grid.Column="0" BackgroundColor = "{Binding Source = {x:Static MyNamespace.Mobile:UserInterfaceDefinitions.Colors} }" />
</Grid>
</ContentPage.Content>
</ContentPage>
Code Behind .cs
using MyNamespace.Mobile.UI.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyNamespace.Mobile.UI
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestAndDemoSelection : ContentPage
{
public TestAndDemoSelection()
{
InitializeComponent();
}
}
}
How to bind the static class property to XAML ?
I have got the resolutions. It was because of Nested Static class was not accessible inside the XAML the correct code as below.
user defined static class:
namespace MyNamespace.Mobile
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public static class UserInterfaceDefinitions
{
public static string BackgroundColor { get; } = "#DCECEC";
}
}
XAML file:
<?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:MyNamespace.Mobile"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" BackgroundColor = "{Binding Source = {x:Static local:UserInterfaceDefinitions.BackgroundColor}}" />
</Grid>
</ContentPage.Content>
</ContentPage>
In order to bind on a Static Property:
1) Declare the namespace to import using xmlns
2) Use the xmlns accordingly in Source
=>
<?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:buttons="clr-namespace:MyNamespace.Mobile.UI.Buttons"
xmlns:Status="clr-namespace:MyNamespace.Mobile.UI.StatusDetails"
xmnlns:local="clr-namespace:MyNamespace.Mobile"
x:Class="MyNamespace.Mobile.UI.TestAndDemoSelection">
<ContentPage.Content Margin="0,0,0,0" BackgroundColor="White">
<Grid x:Name="ChildGrid" Grid.Row="1" Grid.Column="0" ColumnSpacing="10" BackgroundColor="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="0" BackgroundColor = "{x:Static local:UserInterfaceDefinitions.Colors.BackgroundColor}" />
</Grid>
</ContentPage.Content>
</ContentPage>
Moreover, BackgroundColor should be a property in order to be accessible:
public static string BackgroundColor {get;} = "#DCECE";
XAML works very poorly with nested classes.
Yes, and in general, a public nested class is often a very bad technique.
Example:
namespace MyNamespace.Mobile
{
public static class Colors
{
public static string BackgroundColor { get; } = "Red";
}
}
XAML:
<StackPanel xmlns:Circassia.Mobile="clr-namespace:MyNamespace.Mobile"
Background ="{Binding Source={x:Static Circassia.Mobile:Colors.BackgroundColor}}"/>
Second example:
namespace MyNamespace.Mobile
{
public static class UserInterfaceDefinitions
{
public static ColorsClass Colors{ get; } = new ColorsClass();
public class ColorsClass
{
private static readonly string s_BackgroundColor = "Red";
public static string BackgroundColor { get; } = s_BackgroundColor;
}
}
}
XAML:
<StackPanel xmlns:Circassia.Mobile="clr-namespace:MyNamespace.Mobile"
Background ="{Binding BackgroundColor, Source={x:Static Circassia.Mobile:UserInterfaceDefinitions.Colors}}"/>

Is instantiating a class in VM, MVVM compliant ? How else if so?

I have a contentpage and a ContentView with the content property bound to the view model
MainPage:
`
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MvvM.Views.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MvvM.Views"
xmlns:vm="clr-namespace:MvvM.ViewModels">
<!-- ViewModel BindingContext -->
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<Grid>
<Grid.RowDefinitions>
<!-- Header Row -->
<RowDefinition Height="50" />
<!-- ContentView Row -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header -->
<Grid Grid.Row="0"
BackgroundColor="CornflowerBlue"
VerticalOptions="FillAndExpand">
<!-- Button On Header -->
<Button Command=""
Text="Page Switch"
VerticalOptions="Center">
<Button.GestureRecognizers>
<TapGestureRecognizer Command="TapGestureCommand" />
</Button.GestureRecognizers>
</Button>
</Grid>
<!-- Content Container -->
<Grid Grid.Row="1" VerticalOptions="Center">
<ContentView Content="{Binding DisplayPage}" />
</Grid>
</Grid>
</ContentPage>
`
ViewModel:
`using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using MvvM.Views;
using Xamarin.Forms;
namespace MvvM.ViewModels
{
public class MainViewModel :INotifyPropertyChanged
{
public MainViewModel()
{
DisplayPage = new Views.MainPage();
}
private ContentPage _displayPage;
public ContentPage DisplayPage
{
get { return _displayPage; }
set
{
if (value != _displayPage)
{
_displayPage = value;
}
}
}
private ContentView _contentToDisplayView;
public ContentView SelectedView
{
get => _contentToDisplayView;
set
{
_contentToDisplayView = value;
OnPropertyChanged();
}
}
public Command TapGestureCommand
{
get
{
return new Command(TapGesture);
}
}
private void TapGesture()
{
_contentToDisplayView = new RedView();
_displayPage.Content = _contentToDisplayView.Content;
OnPropertyChanged();
}
#region PropertyChangedHandler
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}`
and the second page called "RedPage" want to access the content from
`
<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Class="MvvM.Views.RedView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MvvM.ViewModels"
BindingContext="vm:MainViewModel">
<ContentView.Content>
<Grid Width="*"
Height="*"
BackgroundColor="Red" />
</ContentView.Content>
</ContentView> `
The outcome I want is the ContentView content on the RedPage to be displayed in the mainpage contentview.
is creating an instance of the redpage in the view model MVVM complaint ? (I feel that this would tightly bind view to view model?)
how else can i get the content property on red page into the view model ?(cant bind it and sets elements in it as you can only set content property once)
Ideally you would want the ViewModel not to know anything about the View and vice versa, so from that perspective this is not something you would want.
To overcome this, you would want ViewModel-to-ViewModel navigation. So, you just specify to which ViewModel you want to go and the associated View will be loaded. You can implement this manually, and depending on your chosen implementation you would have some way of resolving a View that is linked to that ViewModel.
One way to do this would be by naming conventions and reflection. This means you name all your pages like:
MyPage
YourPage
OurPage
And all the ViewModels like:
MyPageModel
YourPageModel
OurPageModel
Then with reflection you can simply strip off the "Model" suffix and resolve the page from there. Note that I use the Page and PageModel naming, but of course this works for View and ViewModel as well. After you do, you will still have to account for the navigation to and from this views, is it modal or not, etc.
While you can implement all of this manually it would probably be worth while to look into a MVVM framework. The method I just described is how FreshMvvm does this for instance. But there are other good frameworks out there like Prism, Exrin, MvvmCross, etc.

Viewcell XAML + CS throws Build action 'Page' is not supported error

I am trying to link my XAML ViewCell with the c# counterpart and use it with listview.
WeatherCell.xaml
<?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:Name="cell"
x:Class="UI.WeatherCell">
<ViewCell.View>
<StackLayout Orientation="Vertical" Padding="10">
<Label Text="WeatherCell"
x:Name="TempLabel"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Label Text="WeatherCell"
x:Name="LocationLabel"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ViewCell.View>
</ViewCell >
WeatherCell.cs
namespace UI
{
public partial class WeatherCell : ViewCell
{
public WeatherCell()
{
InitializeComponent();
}
}
}
Referred in MainPage.cs as follows
this.WeatherListView.ItemsSource = Weather.Weather.DataFactory.genForecast();
this.WeatherListView.ItemTemplate = new DataTemplate(typeof(WeatherCell));
While building I get error as
'Page' is not supported by the specific combination of the project's targets. \WeatherCell.xaml.
My guesss was x:Class="UI.WeatherCell" will link both the xaml and cs. What am I doing wrong?
Changing build action for WeatherCell.xaml fixed the problem.
it has to be set to EmbeddedResource
Build Action property can be found in file properties context menu.
Right Click the xaml file and click Properties.
Under Properties select Embedded Resource.
Rebuild your project.

Circular referenced IValueConverter in Application.Resources

I'm getting the error :
StaticResource not found for key maxLength
the setup is as follows:
Converter setup in app.xaml, which also contains a datatemplate
<Application.Resources>
<ResourceDictionary>
<ext:MaxLengthStringConverter x:Key="maxLength"/>
....
<DataTemplate x:Key="HotelViewModel">
<tripSegmentPartViews:HotelView
Padding="0"
HeightRequest="60"
BorderWidth="1"
BorderColor="{ext:ColourResource Divider}"
BordersToDraw="{x:Static controls:Borders.Top}"
BackgroundColor="Transparent"/>
</DataTemplate>
....
view in the HotelView.xaml which is in the datatemplate, uses the converter
....
<Label Text="{Binding HotelName, Converter={StaticResource maxLength}, ConverterParameter=10}"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="1,0.2,0.62,0.5"
VerticalOptions="End"
HorizontalOptions="Start"
FontSize="20"
/>
....
If I move the converter to HotelView.xaml resource dictionary it works
If I change the reference to a DynamicResource it is not used
Obviously with something as basic as max length (which shortens the string and adds '...' if its over the required length) I want to be able to use it through out the application, and not have to reference it in multiple resource dictionaries.
Is this a bug?
----------------- edit ------------------
OK I have reproduced this errror with a minimum app consisting of:
App1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App1.App"
xmlns:ext="clr-namespace:App1.Extensions;assembly=App1"
xmlns:local="clr-namespace:App1;assembly=App1">
<Application.Resources>
<ResourceDictionary>
<ext:MyConverter x:Key="conv"></ext:MyConverter>
<DataTemplate x:Key="dt">
<local:View1></local:View1>
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Page1.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"
x:Class="App1.Page1"
xmlns:local="clr-namespace:App1;assembly=App1">
<StackLayout>
<Label Text="Page1" VerticalOptions="Center" HorizontalOptions="Center" TextColor="White" />
<ListView ItemTemplate="{StaticResource dt}" ItemsSource="List">
</ListView>
</StackLayout>
</ContentPage>
View1.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="App1.View1"
xmlns:ext="App1.Extensions">
<Label Text="{Binding MainText, Converter={StaticResource conv}" VerticalOptions="Center" HorizontalOptions="Center" TextColor="White"/>
</ContentView>
App1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace App1
{
public partial class App : Application
{
public App()
{
InitializeComponent();
// The root page of your application
Page1 p = new Page1();
p.BindingContext = new {
MainText = "test",
List = new List<string>() { "test"}
};
var navContainer = new NavigationPage(p);
navContainer.BarBackgroundColor = Color.Red;
navContainer.BarTextColor = Color.White;
MainPage = navContainer;
}
}
}
The error is thrown at runtime using the VS emulator
From what you mention you want to be able to define a IValueConverter the once, and use it from any Xamarin.Forms ContentPage, without the need to keep specifying the converter in the local XAML page.
This can be achieved by doing the following:-
In your PCL you normally have App.cs.
You will need to delete this, and add a new Forms Xaml Page called App.cs.
This will generate both the App.xaml and related App.cs files.
In this question, (How can I databind an image?), there is a converter called MyByteToImageSourceConverter.
I will illustrate using this:-
App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SampleApp.App"
xmlns:local="clr-namespace:{namespace reference goes here to the converter}"
>
<Application.Resources>
<ResourceDictionary>
<local:MyByteToImageSourceConverter x:Key="kyByteToImageSourceConverter"/>
</ResourceDictionary>
</Application.Resources>
</Application>
So in the above we have defined our converter with a key, that we will then be able to reference from all other Xamarin.Forms ContentPage's.
App.cs
namespace SampleApp
{
public partial class App
: Xamarin.Forms.Application
{
public App()
{
InitializeComponent();
//
this.MainPage = new ByteToImageExample2();
}
}
}
In the code-behind we need to change the default inheritance from ContentPage and specify Xamarin.Forms.Application.
We also specify our launch page, via the this.MainPage = ...
ByteToImageExample2.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"
x:Class="SampleApp.ByteToImageExample2"
>
<StackLayout>
<Image Source="{Binding MyImageAsBytes, Converter={StaticResource kyByteToImageSourceConverter}}"/>
</StackLayout>
</ContentPage>
In our ContentPage we can see above we are referencing the converter that we specified in App.xaml via the StaticResource kyByteToImageSourceConverter.
As that was definied in App.xaml, we can re-use this in all our pages without the need to specify the location of the converter locally.
For completeness the code-behind is:-
ByteToImageExample2.cs:-
public partial class ByteToImageExample2 : ContentPage
{
public ByteToImageExample2()
{
InitializeComponent();
//
byte[] bytImage = { your image as a byte collection }
//
this.BindingContext = new MyImageViewModel()
{
MyImageAsBytes = bytImage
};
}
}
Update 1:-
You can have the following in your App.xaml:-
<DataTemplate x:Key="kyByteToImage3ExampleDataTemplate2">
<ViewCell>
<local2:MyCustomView1/>
</ViewCell>
</DataTemplate>
with local2:MyCustomView1 referencing your custom view, which for this example is defined as:-
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SampleApp.MyCustomView1">
<Image Source="{Binding MyImage, Converter={StaticResource kyByteToImageSourceConverter}}" Aspect="AspectFit" />
</ContentView>
This custom view still uses a Converter as specified from the App.xaml and does still render, without the need to specify the Converter locally within the ContentView class.