I have a XAML element that I want to style, but as it is inside of a dynamic list (which I set using Name=""), I can't see any of my changes while writing the XAML.
Is there a way so that Visual Studio renders one (or a few) test element(s), so that I can see what I am doing?
If you set the DataContext of the control then the XAML Designer will pick up any data from it.
<UserControl.Resources>
<local:MyViewModel x:Key="MyViewModel"/>
</UserControl.Resources>
<ListBox DataContext="{StaticResource MyViewModel}" ItemsSource="{Binding Items}">
</ListBox>
public class MyViewModel
{
public string[] Items { get; set; }
public MyViewModel()
{
Items = new[] { "Item1", "Item2", "Item3" };
}
}
Related
I have created a simple UWP app. All I want is, whenever the user clicks on the AutoSuggestBox, it needs to show all the items in the ItemsSource as suggestions. A combobox is working fine when I set the DisplayMemberPath but the AutoSuggestBox upon clicking doesn't show the ItemsSource as suggestions. Please help. (In this case when I click on the AutoSuggestBox, it needs to display ABC, BCD)
xaml: MainPage.xaml
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<ComboBox Width="120"
ItemsSource="{Binding TestList,Mode=OneWay}"
SelectedIndex="0"
DisplayMemberPath="Name"/>
<AutoSuggestBox Width="200"
Margin="0,20,0,0"
ItemsSource="{Binding TestList,Mode=OneWay}"
DisplayMemberPath="Name"
TextMemberPath="Name"
PlaceholderText="Search"/>
</StackPanel>
Code Behind: MainPage.xaml.cs
public class Test
{
public string Name { get; set; }
public int Id { get; set; }
}
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private List<Test> _testList;
public List<Test> TestList
{
get
{
_testList = new List<Test>();
_testList.Add(new Test()
{
Name = "ABC",
Id = 1,
});
_testList.Add(new Test()
{
Name = "BCD",
Id = 2,
});
return _testList;
}
}
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
}
In this case when I click on the AutoSuggestBox, it needs to display ABC, BCD
Please refer AutoSuggestBox document, Represents a text control that makes suggestions to users as they enter text using a keyboard or pen (using ink and handwriting recognition). it will filter your data based on the input. Then, set the filtered data as the ItemsSource of the AutoSuggestBox to update the suggestion list. So the drop list only rendered when you typing. and it will not display the drop-list when you click the AutoSuggestBox.
For this scenario, the best practice is using ComboBox to replace.
I'm trying to achieve what I think is probably quite simple but as I'm new to Xamarin & Databinding I think I'm getting in a spin.
I have a very simple ContentPage that just has a Databinding to my viewModel for this page and my ContentView, TotalsTemplate.
<ContentPage.BindingContext>
<vm:DealsTodayViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<template:TotalsTemplate></template:TotalsTemplate>
</StackLayout>
</ContentPage.Content>
My viewmodel has a public property of my class, Totals, which has basic int,string,decimal props.
public class DealsTodayViewModel
{
Public string ViewModelPeriod;
public PeriodTotals Totals;
public DealsTodayViewModel()
{
ViewModelPeriod = "TODAY";
Totals = new PeriodTotals
{
Period = "DAILY",
ClientServices_Deals_Chicago = 1,
ClientServices_Deals_Manchester_Na = 1,
ClientServices_Deals_Manchester_Uk = 1,
ClientServices_Ramp_Chicago = 1.2m,
ClientServices_Ramp_Manchester_Na = 1.3m,
ClientServices_Ramp_Manchester_Uk = 1.4m
};
}
}
Now in my TotalsTemplte ContentView I have a Grid with following inside.
<Label Text="{***Binding ViewModelPeriod***}" FontAttributes="Bold"/>
<Frame OutlineColor="Black" Grid.Row="0" Grid.Column="1">
<Label Text="{Binding ***Totals.Period***}" FontAttributes="Bold"/>
</Frame>
My String property on the DealsTodayViewModel is visible in my ContentView but not the Perod property from inside my Totals property, am I binding incorrectly to this?
From the document, data-binding should binding between properties instead of field:
Data binding is the technique of linking properties of two objects so
that changes in one property are automatically reflected in the other
property. Data binding is an integral part of the Model-View-ViewModel
(MVVM) application architecture.
So the solution is change the fields in your vm to properties:
public class DealsTodayViewModel
{
public string ViewModelPeriod { get; set; }
public PeriodTotals Totals { get; set; }
public DealsTodayViewModel()
{
...
}
}
Refer: field and property
I'm attempting to get my head around MVVM with XamarinForms and I'm slightly confused with regards to proper partitioning of functionality:
I have a main page, MainPage.xaml, which includes a stacklayout:
<StackLayout x:Name="MainPageStackLayout">
...
</StackLayout>
Within this stacklayout I have Picker which is bound as follows:
<Picker Title="Select a background colour"
TitleColor="Black"
TextColor="Black"
ItemsSource="{Binding MyColours}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding selectedBackGroundColour}" SelectedIndexChanged="BackGroundColourPicker_SelectedIndexChanged"/>
Following the article from microsoft (https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/userinterface-monkeyapppicker/):
I have a "View" which basically defines the layout of my page.
A "ViewModel" which holds an IList "MyColours" and a variable "SelectedBackGroundColour".
A "Model" which defines the MyColour class. A MyColour has a string name and a Xamarin.Forms.Color (from a hex value, both populated on start up).
This all works fine. I can start up the app and the Picker populates with the colours I add to "MyColours". If I change the index then my SelectedBackGroundColour also updates, has the correct name and a different RGB value.
However, I'm lost as to where I would tie in the updating of the actual background colour of the MainPageStackLayout. The View (MainPage.xaml.cs) picks up the "BackGroundColourPicker_SelectedIndexChanged" event but what is the standard practice for reading from the view model (where SelectedBackGround colour is actual defined ?)
I have a feeling I can bind Background colour in the MainPageStackLayout xaml view so I wont have to catch the selected index change event.
Thanks all.
According to your description, I guess that you want to change MainPage StackLayout BackGround color by Picker value, am I right?
If yes, please follow the steps below.
Firstly, please confirm that you implement INotifyPropertyChanged interface to notify SelectedBackGroundColour changed.
Then there are full code, please take a look:
<StackLayout x:Name="MainPageStacklayout" BackgroundColor="{Binding selectedBackGroundColour.color}">
<Picker
x:Name="picker1"
Title="Select a background colour"
ItemDisplayBinding="{Binding name}"
ItemsSource="{Binding MyColours}"
SelectedItem="{Binding selectedBackGroundColour}"
TextColor="Black"
TitleColor="Black" />
</StackLayout>
public partial class Page5 : ContentPage, INotifyPropertyChanged
{
public ObservableCollection<MyColour> MyColours { get; set; }
private MyColour _selectedBackGroundColour;
public MyColour selectedBackGroundColour
{
get { return _selectedBackGroundColour; }
set
{
_selectedBackGroundColour = value;
RaisePropertyChanged("selectedBackGroundColour");
}
}
public Page5()
{
InitializeComponent();
MyColours = new ObservableCollection<MyColour>()
{
new MyColour(){name="red",color=Color.Red},
new MyColour(){name="gray",color=Color.Gray},
new MyColour(){name="BlueViolet",color=Color.BlueViolet}
};
selectedBackGroundColour = MyColours[0];
this.BindingContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class MyColour
{
public string name { get; set; }
public Color color { get; set; }
}
The screenshot:
I am new to Xamarin. I have a requirement where I have to implement a ListView or say tableView that have multiple different type-size cells.
And I also have to add Header for a particular section of cells, and some of my custom cells have a horizontal scroll in it.
I have done this thing in iOS native UITableView before, but don't know how this done in Xamarin cross platform, can anyone help me out this?
You are looking for DataTemplateSelector, which is very well documented in the official Xamarin.Forms documentation.
The basics are that you create your own DataTemplateSelector class:
public class MyDataTemplateSelector : DataTemplateSelector
{
}
In that class you override OnSelectTemplate:
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
}
By checking the type of the item argument, you should be able to figure out which template to return.
So lets say you have a ViewModel for Dog and one for Cat and want to show a different DataTemplate for each of those. You would do something like:
public class DogCatTemplateSelector : DataTemplateSelector
{
public DataTemplate DogTemplate { get; set; }
public DataTemplate CatTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is DogViewModel)
return DogTemplate;
return CatTemplate;
}
}
Then you can consume this in your XAML:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="dogTemplate">
<ViewCell>
... <---- define your look of dog template here
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="catTemplate">
<ViewCell>
... <---- define your look of cat template here
</ViewCell>
</DataTemplate>
<local:DogCatTemplateSelector x:Key="dogCatTemplateSelector"
DogTemplate="{StaticResource dogTemplate}"
CatTemplate="{StaticResource catTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
Then simply set the ItemTemplate to your dogCatTemplateSelector instance you've defined in the resources on your ListView:
<ListView ItemsSource="{Binding DogsCatsCollection}" ItemTemplate="{StaticResource dogCatTemplateSelector}" />
Your ViewModel would then look something like:
public class Animal : INotifyPropertyChanged
{
}
public class DogViewModel : Animal
{
}
public class CatViewModel : Animal
{
}
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<Animal> DogsCatsCollection { get; }
= new ObservableCollection<Animal>();
}
Then you just populate DogsCatsCollection with instances of dogs and cats.
I have a strange problem in my WinRT/C# XAML Metro app, using the Windows 8 Release Preview (latest patches installed). I'm using a ComboBox, whose values ItemsSource and SelectedValue are bound to properties in a ViewModel:
<ComboBox SelectedValue="{Binding MySelectedValue, Mode=TwoWay}"
ItemsSource="{Binding MyItemsSource, Mode=OneWay}"
Width="200" Height="30" />
Code behind:
public MainPage()
{
this.InitializeComponent();
DataContext = new TestViewModel();
}
And a very simple definition of the TestViewModel, using strings:
public class TestViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private IEnumerable<string> _myItemsSource = new List<string>
{
"Test Item 1",
"Test Item 2",
"Test Item 3"
};
public IEnumerable<string> MyItemsSource
{
get { return _myItemsSource; }
}
private string _mySelectedValue = "Test Item 2";
public string MySelectedValue
{
get { return _mySelectedValue; }
set
{
_mySelectedValue = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("MySelectedValue"));
}
}
}
}
Now I thought this simple solution should just work... But when I start the app, the SelectedValue="Test Item 2" doesn't show up, the ComboBox is left empty. By setting breakpoints I noticed that the bound values MyItemsSource and MySelectedValue are corectly retrieved from the View Model when I set the DataContext of the view. After this action, the ComboBox.SelectedValue property is actually set to "Test Item 2", but it just doesn't show! Also I noticed that when I change the selected value in the ComboBox by user action on the UI, the changed value shows up in the ComboBox and the View Model property is updated accordingly. So everything seems to work fine except the initial visualization of the MySelectedValue View Model property. I'm becoming really desperate about that...
Now while this is the simplest example, in the origin I wanted to bind whole entities to ComboBox, setting DisplayMemberPath and SelectedValuePath. Unfortunately, the same problem occurs.
I found the problem in my example: In the XAML markup I've defined the SelectedValue property before the ItemsSource property. If I swap both definitions in this way, it works:
<ComboBox ItemsSource="{Binding MyItemsSource, Mode=OneWay}"
SelectedValue="{Binding MySelectedValue, Mode=TwoWay}"
Width="200" Height="30" />
This is really odd and annoying. Now I would like to know: is this a bug or by design? I think this is a bug, because the control should be working regardless of the order of the defined properties in XAML.
this is working solution : you can find here https://skydrive.live.com/?cid=b55690d11b67401d&resid=B55690D11B67401D!209&id=B55690D11B67401D!209
<ComboBox Width="300" Height="32" HorizontalAlignment="Left" DisplayMemberPath="Name"
VerticalAlignment="Top" ItemsSource="{Binding PersonCollection}"
SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></ComboBox>
ViewModle class is
public class ViewModel:BaseViewModel
{
private Person selectedPerson;
public Person SelectedPerson {
get { return this.selectedPerson; }
set { this.selectedPerson = value;
this.RaisePropertyChanged("SelectedPerson");
}
}
public ObservableCollection<Person> PersonCollection { get; set; }
public ViewModel()
{
this.PersonCollection = new ObservableCollection<Person>();
this.PopulateCollection();
//setting first item as default one
this.SelectedPerson = this.PersonCollection.FirstOrDefault();
}
private void PopulateCollection()
{
this.PersonCollection.Add(new Person { Name="Oscar", Email="oscar#sl.net" });
this.PersonCollection.Add(new Person { Name = "Jay", Email = "jay#sl.net" });
this.PersonCollection.Add(new Person { Name = "Viral", Email = "viral#sl.net" });
}
}