xamarin datatemplateselector: not valid XAML name - xaml

I'm trying to do a very common usage of Xamarin.Forms ListView, where I have multiple types of items.
I'm using a DataTemplateSelector and defining the different (two at this point) views in my XAML file. That requires referencing the c# code from the XAML code through a namesspace definition. And, that's where I'm stuck.
The error I'm getting is
XFC0000 Cannot resolve type "local:NodeTemplateSelector".
Here is my XAML, condensed:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
...
xmlns:local="clr-namespace:varlist">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="NoteItem">
...
</DataTemplate>
<local:NodeTemplateSelector x:Key="NodeTemplateKey">
NoteTemplate = "{StaticResource NoteItem}"
ImageTemplate = "{StaticResource ImageItem}"
</local:NodeTemplateSelector>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
And, here is C#, also condensed:
namespace varlist
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ListViewPage : ContentPage
{
...
public class NodeTemplateSelector : DataTemplateSelector
{
public DataTemplate NoteTemplate { get; set; }
public DataTemplate ImageTemplate { get; set; }
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
ListView list = (ListView)container;
if (item is NoteData)
return NoteTemplate;
else // item is ImageData
return ImageTemplate;
}
}
}
}
What do I need to change to get the XAML to recognize NodeTemplateSelector ?

As Jason and Shaw suggested, the NodeTemplateSelector must be in top level class.
Also, another problem I ran into is the syntax in the DataTemplate XAML file. Might as well add this note, in case anyone else has the same trouble:
The NodeTemplateSelector in XAML must be defined as direct content; must be like this:
<local:NodeTemplateSelector
x:Key="NodeTemplate"
NoteItemTemplate="{StaticResource NoteTemplate}"
ImageItemTemplate="{StaticResource ImageTemplate}"
/>
Otherwise you get a rather undecipherable runtime error.

Related

How do I make a generic ContentPage that uses Type parameters?

If I need to post more code, then let me know, but I think what I have is sufficient to convey what I am trying to do. I can do it if I don't use XAML to define the page content, but when I try it with XAML, addng the <TViewModel,TDataModel> causes InitializeComponent() and any named elements in the XAML to get flagged as not found.
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BaseSelectListPage<TViewModel,TDataModel> : ContentPage
where TViewModel : BaseSelectListViewModel<TDataModel>, new()
{
private TViewModel _viewModel { get; set; }
public BaseSelectListPopup()
{
_viewModel = new TViewModel();
BindingContext = _viewModel;
InitializeComponent(); // InitializeComponent gets flagged as not found
ExampleElement.Spacing = 5; // ExampleElement also gets flagged as not found
}
// rest of class
}
I don't know how to define the generic types in XAML, but here is what I tried.
<ContentPage 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"
mc:Ignorable="d"
x:Class="IRA.Views.SelectLists.BaseSelectListPage<TViewModel,TDataModel>">
<!-- this is obviously what I don't know how to do ^^^^ -->
<ContentPage.Content>
<StackLayout x:Name="ExampleElement">
<Label Text="Thanks for helping"/>
</StackLayout>
<!-- various elements -->
</ContentPage.Content>
</ContentPage>

How to preview a ListView using Xamarin.Forms xaml editor

I'm implementing a ListView in Xamarin.Forms with custom cells, but I can't see what I'm doing since the preview shows an empty list and re-building every time is simple too time consuming. I can't even see a simple TextCell..
How can I see the preview of my cells in the editor? This is my 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:MyNamespace"
x:Class="MyNamespace.MyAppPage">
<ContentPage.Content>
<ListView x:Name="myList">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="Preview?" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
Note: I am using Visual Studio 2017 for Mac.
2nd Part
OK so I tried using BindingContext but I don't understand well the usage of this property. This is my updated 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:MyNamespace;assembly:MyNamespace"
BindingContext="{x:Static local:MusicSeed.Model}"
x:Class="MyNamespace.MyAppPage">
<ContentPage.Content>
<ListView ItemsSource="{Binding Tracks}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
And this is where I have the data, MusicSeed.cs:
namespace MyNamespace
{
public static class MusicSeed
{
public static readonly MusicSeedModel Model = new MusicSeedModel();
}
public class MusicSeedModel
{
public readonly MusicTrack[] Tracks =
{
new MusicTrack("Track 01"),
new MusicTrack("Track 02"),
new MusicTrack("Track 03"),
new MusicTrack("Track 04"),
};
}
}
The result is this error thrown by the XAML editor:
No static member found for local:MusicSeed.Model
I tried changing Tracks as static but nothing changed. Also rebuilt the solution, the error disappeared but the preview is still empty. What am I missing here?
You will have to provide some kind of BindingContext for rows to be rendered during design time. There is an awesome article by James Montemagno that explains how to do just that.
Another recommended article to refer would be this one on Xamarin Help
EDIT 1:
Your XAML is correct, but the view-model is wrong. You can only bind to properties. Try changing you declaration to following:
namespace MyNamespace
{
public class MusicSeed
{
public static MusicSeedModel Model { get; } = new MusicSeedModel();
}
public class MusicSeedModel
{
public MusicTrack[] Tracks { get; } =
{
new MusicTrack("Track 01"),
new MusicTrack("Track 02"),
new MusicTrack("Track 03"),
new MusicTrack("Track 04"),
};
}
public class MusicTrack
{
public string Name { get; }
public MusicTrack(string v)
{
this.Name = v;
}
}
}
You can't. If you are using MVVM framework, your code still needs to be generated / Build.
An Alternative is to use Xamarin Live Player Which Can Build Lists On your actual device for android and ios
FYI: Currently while answering this questions it's on Alpha

Property can't be found on ViewModel in UWP app

An Order form in UWP using Template 10 adds products to an order. The error is
Invalid binding path 'OrderViewModel.FindProduct_TextChanged' : Property 'OrderViewModel' can't be found on type 'ProductViewModel'
The relevant xaml snippet is
<Page.DataContext>
<ViewModels:MainPageViewModel x:Name="OrderViewModel" />
</Page.DataContext>
<GridView ItemsSource="{x:Bind OrderViewModel.Products, Mode=TwoWay}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="ViewModels:ProductViewModel" >
<AutoSuggestBox
Name="ProductAutoSuggestBox"
TextMemberPath="{x:Bind ItemCode, Mode=TwoWay}"
TextChanged="{x:Bind OrderViewModel.FindProduct_TextChanged}">
</AutoSuggestBox>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The relevant snippet from the OrderViewModel and the ProductViewModel
namespace ViewModels
{
public class OrderViewModel : ViewModelBase
{
public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();
public void FindProduct_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{ ... }
}
public class ProductViewModel : ViewModelBase
{
string _ItemCode = default(string);
public string ItemCode { get { return _ItemCode; } set { Set(ref _ItemCode, value); } }
public ProductViewModel()
{
}
}
}
How to I correctly reference FindProduct_TextChanged on the OrderViewModel from the DataTemplate for the GridView which references ProductViewModel?
Voted up to #tao's comment. #Vague, I think you may misunderstand what x:DataType is used for. You can refer to the "DataTemplate and x:DataType" part of Data binding in depth:
When using {x:Bind} in a data template, so that its bindings can be validated (and efficient code generated for them) at compile-time, the DataTemplate needs to declare the type of its data object using x:DataType.
For your scenario, from your code public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();, the type of your DataTemplate's data object should be your Product class, not your ProductViewModel, and in the meanwhile, your FindProduct_TextChanged event must be find in this Product class, that means your code of FindProduct_TextChanged should be placed in your Product data model.
By the way, I think there is no need to use TwoWay binding for ItemsSource. For this scenario, the binding target is ItemsSource of GridView, the binding source is ObservableCollection<Product> Products, I understand you want to update GridView when your collection is updated, this is work is done with ObservableCollection. Besides, only the binding source here can be changed to notify the binding target, so OneWay binding is enough. But it's not a big problem with your code.
So for your GridView, it should be something like this:
<GridView ItemsSource="{x:Bind OrderViewModel.Products, Mode=OneWay}">
<GridView.ItemTemplate>
<DataTemplate x:DataType="Models:Product" >
<AutoSuggestBox
Name="ProductAutoSuggestBox"
TextMemberPath="{x:Bind ItemCode, Mode=TwoWay}"
TextChanged="{x:Bind FindProduct_TextChanged}">
</AutoSuggestBox>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
if error is kind of like this I approved its a charset support bug:
Error Invalid binding path 'XX.YY' : Property 'ZZ' can't be found on type 'CCC'
Either xaml and C# supports unicode;
its because you use a non-ascii character in class properties. this is a bug I found today. Just rename your class proprty characters to ascii standards. Hope it will be fixed.

Page with type parameter

I would like to use new feature of UWP -> x:Bind. In order to that, all my pages need to have ViewModel property (as described in tutorials).
To avoid code duplicity, I have established base class as follows:
public abstract class BasePage<TBaseVM> : Page, where TBaseVM : BaseVM
{
public TBaseVM VM { get; private set; }
protected BasePage()
{
DataContextChanged += (s, e) => VM = e.NewValue as TBaseVM;
}
}
As you can see this BasePage class contains property called "VM" and property is of type BaseVM. Hence, I don't need to define VM property on each derived class.
Then I created derived page 'MainPage' defined in xaml as follows:
<pages:BasePage
x:Class="Realarm.View.Pages.MainPage"
x:TypeArguments="viewModel:MainVM">
By doing that, even Resharper's Intellisense offers me properties from "MainVM" in MainPage.xaml, thus is can write:
<ListView ItemsSource="{x:Bind VM.AlarmsVM}">
Unfortunately, when I try to build the project, I get error in MainPage.g.i.cs:
Severity Code Description Project File Line
Error CS0305 Using the generic type 'BasePage' requires 1 type arguments Realarm D:...\Realarm\obj\x86\Debug\View\Pages\MainPage.g.i.cs 13
Any help?
I got this working using Xamarin.Forms.
Base Page:
public abstract class BaseContentPage<TViewModel> : ContentPage where TViewModel : BaseViewModel, new()
HomePage.cs:
public partial class HomePage : BaseContentPage<HomeViewModel>
HomePage.xaml:
<d:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="clr-namespace:Sample.Pages;assembly=Sample"
xmlns:vm="clr-namespace:Sample.ViewModels;assembly=Sample"
x:Class="Sample.Pages.HomePage"
x:TypeArguments="vm:HomeViewModel">
<ContentPage.Content>
</ContentPage.Content>
</d:BaseContentPage>
Just add a x:TypeArguments definition at the top of the XAML:
<v:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:v="clr-namespace:YourApp.Views"
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:vm="clr-namespace:YourApp.ViewModels"
mc:Ignorable="d"
x:TypeArguments="vm:HomeViewModel"
x:Class="YourApp.MainPage">
Worked for me as well when I set the BindingContext as given below in Base Page's constructor:
public BasePage()
{
BindingContext = new TBaseVM();
}

XmlnsDefinitionAttribute combined with x:Name causes compilation error with code generation

I have and issue with using the XmlnsDefinition attribute within a silverlight 4 assembly.
Here's the test case:
In AssemblyInfo.cs of the silverlight project I add the following:
[assembly: XmlnsDefinition("urn:foo", "SilverlightApplication1")]
[assembly: XmlnsDefinition("urn:foo", "SilverlightApplication1.SomeNamespace")]
I edit MainPage.xaml.cs and to make it look like so:
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
}
}
namespace SilverlightApplication1.SomeNamespace
{
public class SomeControl : ContentControl
{
}
}
Now in MainPage.xaml I have the following:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:foo="urn:foo">
<Grid>
<foo:SomeControl>
<TextBlock Text="Hello World"/>
</foo:SomeControl>
</Grid>
</UserControl>
This compiles and runs fine. The problem occurs when I add the x:Name attribute to the SomeControl tag.
This does not compile:
<foo:SomeControl x:Name="bar">
<TextBlock Text="Hello World"/>
</foo:SomeControl>
Looking at the .g.i.cs file that gets generated, the control is declared as
internal SomeControl bar;
The file is missing either the using statement or the full type name. I've also tried this in WPF and the results are the same. Can anyone tell me what, if anything, I'm doing wrong?
I have the same issue. Based on my searching, it looks like this is not currently supported.
http://forums.silverlight.net/forums/t/84877.aspx
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/7e7a032a-dad3-4e02-9e5a-d73e346b75ed/