I am working in a Windows Phone 8.1 application (non SL) and have a property on my ViewModel called Apples which has a value of 3.
I want a repeater to draw x Apples (I have the image) where x is the value of Apples on my ViewModel.
How can I achieve this in XAML? I have the following at the moment:
<ItemsControl Grid.Column="0" ItemsSource="{Binding Lives, Converter={}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- image here -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I am guessing I need to somehow convert the integer into some sort of items?
ItemsSource="{Binding SomeNumber, Converter={StaticResource NumberToItemsConverter}}"
public class NumberToItemsConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var number = (int)value;
return Enumerable.Range(1, number);
}
}
You have two options:
Option one
You need to create a list of apples, and bind the ItemsControl to it.
Here's an example:
int x = 3;
Apples = new ObservableCollection<Apple>();
/*your ViewModel must implement INotifyPropertyChanged so the UI will be
notified by the changes in the Apples list*/
for(int i = 0; i < x; i++)
{
Apples.Add(new Apple());
}
//now your ItemsControl has 3 apples
Option two
You create a custom control that does what I wrote above, in the code behind. In that control you create a dependency property of type int, and when that property is changed you can add items to your ItemsControl.
What if you try it out with a GridView with 5 items (each of them styled as an apple). The GridView has its source backed by with ObservableCollection. When a life is "consumed", just remove an item from the collection.
Related
I'm trying to use a custom variable to name UI Elements in XAML in order to use them in my Xamarin code. How would I do that?
I know that I can use the tags
<Label x:Name="CallVariable" Text="This will appear"/>
and I can call the label from Xamarin using
Label foo = FindByName("CallVariable") as Label;
and mess with the text with the following
foo.Text == "This will appear"
which should return true.
I learned about binding, and so I tried to use this in my variables.
<Label x:Name={Binding Name}/>
Label bar = FindByName(emp.training[i] as Label);
Unfortunately, every time I run it, I'm receiving the error:
System.NullReferenceException: Object reference not set to an instance of an object.
I remembered to set the BindingContext. And in case it's important, this is all happening within a list view.
Is x:Name a bindable object? Or is there another method I should be using? Maybe a way to call an object based on its label, or something?
My current task is as follows:
I have a list of people's information. Name, Age, Gender, Email, Location, and a few other pieces of information. I'm trying to get someone to search for certain types of people, have it return a list of everyone in a ListView, and have the person be able to select as many as they want. I did this using a button that adds the person to a list (or removes them from the list if they're already on). If the user chooses to, they should be able to also click "Select All" to add everyone. I've got the individual adding down, I just need to somehow select all of them.
You can't access the label with a listView by x:Name in code behind. Instead of access the label in the listView, you can bind the property of label in code behind. For example:
<ListView x:Name="testListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Desc}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And in code behind, it should be:
public partial class MainPage : ContentPage
{
ObservableCollection<testViewModel> myModels = new ObservableCollection<testViewModel>();
testViewModel model;
public MainPage()
{
InitializeComponent();
testListView.ItemsSource = myModels;
myModels.Add(new testViewModel { Name = "age" });
myModels.Add(new testViewModel { Name = "gender" });
myModels.Add(new testViewModel { Name = "name" });
}
}
class testViewModel
{
public string Name { get; set; }
public string Desc { get; set; }
}
Next time you want to update the text of label:
public void test() {
//Get the model you want to change
model.Desc = "This will appear";
}
I've got the individual adding down, I just need to somehow select
all of them.
I don't know how you implement the individual adding down, share the code and maybe I can give you some suggestions.
I have a converter which takes in the ListView as a parameter to for each item as the List, and then, using the ItemsSource and IndexOf, I can determine the items position in the list and return that as a number for the View:
public class MyConverter : IValueConverter, IMarkupExtension
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var listView = parameter as ListView;
var collection = listView.ItemsSource as IList;
object item = value;
var answer = collection.Count - collection.IndexOf(item); //I'm actually numbering items in reverse.
return answer;
}
}
I bind to it using the entire binding context ( {Binding .} ) so that each item is passed as a value to it's own converter, like so:
<ListView x:Name="ListViewItself" ItemsSource="{Binding TheItemSource}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding ., Converter={converters:MyConverter}, ConverterParameter={x:Reference ListViewItself}}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This works very well. As I add items to my list, the converter correctly calculates the right item place.
My issue now, is that when I remove items from the collection and the ListView, the values for each remaining item in the ListView should automatically update, so as to take into account their new positions. But this is not the case. The converters are called, but with many null values for the items.
I want to know, how can I call RaisePropertyChanged for each binding context in the list so that the converter fires properly for all of them?
Edit:
I try to use
RaisePropertyChanged(nameof(TheItemSource)) when I remove an item from the collection, but it doesn't fire the converter for each item like I'd expect.
I want to display some text in a Xamarin forms ListView grid, based on the comparison of 2 date properties. I have a converter to compare the dates and return a string. What I am trying to do (without success) is pass the entire object to the converter.
XAML:
<ResourceDictionary>
<converters1:CancelConverter x:Key="CancelConverter" />
</ResourceDictionary>
...
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label Grid.Column="0" Text="{Binding ., Converter={StaticResource CancelConverter}}" />
</Grid>
</ViewCell>
</DataTemplate>
Converter:
public class CancelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Schedule schedule = ((Schedule)value);
DateTime date1 = schedule.ProposedCollectionDate;
DateTime date2 = schedule.OrderDate;
if (date1.CompareTo(date2) < 0)
{
return "Cancel this order";
}
}
}
The problem is that in the converter, value is null. How can I pass the object to the Converter, instead of just a single property of the object?
What you have shown looks good to me, but there may be something bad in what you've hidden. I can't tell, but are you properly setting the binding context of the ListView i.e. are you setting the ItemsSource property? From the information you've given, you should be setting it to something like an ObservableCollection<Schedule> or IEnumerable<Schedule> and then each item in the ListView would have a Schedule as its binding context and it would make its way into the value converter happily.
how to change gridview row color based on condition in uwp c#?
I want to highlight the gridview row based on my conditon.
A convenient way to do this would be to put a Border around your GridViewItem and use a ValueConverter to choose the background color based on the current item.
First you define your value converter:
public class ItemToColorConverter: IValueConverter
{
//this converts the item from your data source to the color brush
//of the background of the row
public object Convert(object value, Type targetType,
object parameter, string language)
{
//cast the value parameter to the type of item in your data source
var yourValue = ( YourType )value;
if ( yourValue > 10 ) //some condition you want to use to choose the color
{
//highlight
return new SolidColorBrush( Colors.Green );
}
else
{
//leave no background
return new SolidColorBrush( Colors.Transparent );
}
}
//you don't have to implement conversion back as this is just one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Now you need to create a Application resource instance of the converter in App.xaml:
<Application ...>
<Application.Resources>
<converters:ItemToColorConverter x:Key="ItemToColorConverter" />
</Application.Resources>
</Application>
Now use this converter in your GridView item DataTemplate:
<GridView ItemsSource="{Binding YourDataSource"}>
<GridView.ItemTemplate>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource ItemToColorConverter}">
<!-- ... your content -->
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
I have a ListView whose Data Context is an ObservableCollection. I then used XAML to format the items and bind to their properties in the ListView in ListView.ItemTemplate.DataTemplate . Now, I want to add a TextBlock here to display the position of the item in the ListView through Binding in XAML. How to do that?
If I got your question right, you just need to add a TextBlock in each item DataTemplate with the index number inside the ListView, right?
If so, you can easily do that by doing something like this:
<DataTemplate x:Key="ItemTemplate">
<Grid>
<!--All your various UI elements here...-->
<!--Add a TextBlock with the formatting you want-->
<TextBlock Text="{Binding Position}"/>
</Grid>
</DataTemplate>
And in C#, add something like this after you've created your Source ObservableCollection, before assigning it to the Property inside your ViewModel:
for (int i = 0; i < myCollection.Count; i++)
{
myCollection[i].Position = Convert.ToString(i);
}
//And then, the usual
Source = myCollection
NB: I'm assuming you have a Property called Source in your ViewModel with INotifyPropertyChanged implemented. You will also have to modify the class you use inside your ObservableCollection and add the Position property of course :)