I'm trying to bind some data to a GridView in Windows 8.1's Hub control.
Currently, I have a DataTemplate set up under Page.Resources as follows:
<DataTemplate x:Key="Standard240x320ItemTemplateFAV">
<Grid HorizontalAlignment="Left" Width="320" Height="240">
<Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding FavImage}" Stretch="UniformToFill"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding FavTitle}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="48" Margin="15,0,15,0"/>
</StackPanel>
</Grid>
</DataTemplate>
I then have this HubSection:
<HubSection x:Name="FavHub" Padding="40,60,40,0" >
<DataTemplate>
<GridView
x:Name="itemGridView"
Margin="-4,-4,0,0"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Items In Group"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource Standard240x320ItemTemplateFAV}"
SelectionMode="Single"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
</GridView>
</DataTemplate>
</HubSection>
I use this code to add the DataContext:
FavHub.DataContext = new FavData(Constants.getImage("1002"), "No Favourites");
Where the FavData class is:
public class FavData
{
public static string FavImage { get; set; }
public static string FavTitle { get; set; }
public FavData() { }
public FavData(string itemImageSet, string itemNameSet)
{
FavImage = itemImageSet;
FavTitle = itemNameSet;
}
}
However, no data shows up in the HubSection. What am I doing wrong?
You'll need to bind a list, like a List<FavData> or an ObservableCollection<FavData> to the Hub.
Right now, you've got a GridView that among many other attributes, includes initialization of the ItemsSource property. This property is used as the source for a list of items.
<GridView x:Name="itemGridView"
ItemsSource="{Binding Items}"
</GridView>
The binding is specified as {Binding Items} which means that for whatever object is bound currently to the Hub, grab the List stored on the Items property. As you currently had set a single FavData instance to the Hub via the DataContext property, and it did not have a property called Items, there was nothing to display.
So, my suggestion is to create a list of FavData instances and bind that to the Hub instance instead. If you want to directly bind the list rather than store the list in another "parent" object, you'll also need to adjust the Binding to refer to "self" rather than a specific property. For that, you just use the syntax: {Binding}. It just means, "bind to me." So, the GridView will look for the list of items directly on the bound object (the list of FavData).
<GridView x:Name="itemGridView"
ItemsSource="{Binding}"
</GridView>
And in the C#:
List<FavData> favs = new List<FavData>();
favs.Add(new FavData(Constants.getImage("1002"), "No Favourites"));
FavHub.DataContext = favs;
Related
I can't make the {Binding Title} in the HeaderTemplate appear.
This is the class connected to the BindingContext:
class SensorGroup
{
public string Title { get; set; }
public IList<Sensor> Sensors { get; set; }
}
XAML:
<ListView Header=""
ItemsSource="{Binding Sensors}">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Label Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
...
</ListView>
If I replace it with <Label Text="Some static text"/>, the text appears.
I have found this related question, which links to this other question. But I could not make it work. I tried:
<ContentPage.Resources>
<Label x:Key="MyTitle"
Binding="{Title}"/>
</ContentPage.Resources>
...
<Grid>
<StaticResource ResourceKey="MyTitle"/>
</Grid>
It gives me an error saying that the binding with Title cannot be found.
Sounds you like just need to do:
<ListView Header="{Binding .}"
ItemsSource="{Binding Sensors}">
That is if your ContentPage's BindingContext is set to the SensorGroup class.
The above is telling the ListView.Header to be bound to what ever the ContentPage.BindingContext is set to. That means that the ListView.HeaderTemplate controls will also use what ever ContentPage.BindingContext is set to.
Let me know if that does not make any sense.
How can I refresh ListView after adding item to collection in Windows Store app? Adding items to list works fine, but Listview doesn't refresh. I was trying to implement INotifyCollectionChanged, but what exactly should I do to make it work?
edit: XAML file
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView HorizontalAlignment="Left" Height="437" Margin="10,120,0,0" VerticalAlignment="Top" Width="593" ItemsSource="{Binding Persons, Mode=TwoWay}" Background="#FF5D5D5D">
<ListView.DataContext>
<Model:School/>
</ListView.DataContext>
</ListView>
<Button Content="Button" HorizontalAlignment="Left" Margin="7,64,0,0" VerticalAlignment="Top" Command="{Binding AddCommand, Mode=OneWay}">
<Button.DataContext>
<Model:School/>
</Button.DataContext>
</Button>
</Grid>
C# code:
class School
{
private ObservableCollection<string> _persons = new ObservableCollection<string>()
{
"Name1", "Name2", "Name3"
};
public ObservableCollection<string> Persons
{
get { return _persons; }
}
private ICommand _addCommand;
public ICommand AddCommand
{
get
{
return this._addCommand ??
(this._addCommand = new RelayCommand(Add));
}
}
private void Add()
{
this._persons.Add("Name");
}
}
You don't need to add INotifyCollectionChanged when you are using ObservableCollection - it already implements needed interfaces.
Your code should work, though there may be some other problems:
check if the DataContext of your ListView (its parent in this case) is properly set - it should be set, so that 'ListView would find' Persons property,
also check if the ItemTemplate is properly set - example:
<ListView Name="myList" ItemsSource="{Binding Persons}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Surname}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
in your case there is no need that your ListView's ItemsSource uses TwoWay binding - you are not defining a setter ofr the property Persons.
EDIT:
After your edit, I can see where is the problem - you are setting separate DataContext for your ListView and Button - the button is adding to its own collection - different than ListView is bound to. Take a short test - set the DataContext of both to same staticresource:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Model:School x:Key="mySchool"/>
</Grid.Resources>
<ListView HorizontalAlignment="Left" VerticalAlignment="Stretch" Margin="10,120,0,0" ItemsSource="{Binding Persons}" Background="#FF5D5D5D"
DataContext="{StaticResource mySchool}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="7,64,0,0" VerticalAlignment="Top" Command="{Binding AddCommand, Mode=OneWay}"
DataContext="{StaticResource mySchool}">
</Button>
</Grid>
This is my XAML:
<UserControl x:Class="SearchResultsBox">
<ListBox ItemsSource="{Binding SearchResults}" SelectedItem="{Binding Selected}"
Style="{StaticResource ListBoxStyle1}"
ItemContainerStyle="{StaticResource SearchItemContainerStyle}"
Background="{StaticResource DefaultBackground}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent">
<local:Forecast_SearchResults_ListView_Data/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</UserControl x:Class="SearchResultsBox">
I want to be able to reuse this listbox and just slap on a new datatemplate from the external context:
<local:SearchResultsBox>
<DataTemplate = {ForecastDataTemplate}/>
</local>
And it will put this DataTemplate into the ListBox.ItemTemplate property. Is this even possible? If so, how? If not, is there another way to achieve a similar effect?
you may use as follows
<local:SearchResultsBox ItemTemplate="{StaticResource ForecastDataTemplate}" />
and you can wire up the property to the underlying ListBox
eg
add a name to listbox
<ListBox x:Name="list" ... />
add a property wiring
public DataTemplate ItemTemplate
{
get { return list.ItemTemplate;}
set { list.ItemTemplate = value;}
}
In my Windows Phone 8 I have LongListSelector and ItemTemplate specified for that. In code behind I set the ItemsSource for this LongListSelector. In item template I want to bind value to outside ItemsSource. How to do that?
<DataTemplate x:Key="template">
<TextBlock Text="{Binding name}"/>
<TextBlock Text="{Binding country}"/>
</DataTemplate>
...
<phone:LongListSelector x:Name="list" ItemTemplate="{StaticResource template}">
</phone:LongListSelector>
C#
string country = "Japan";
this.list.ItemsSource = items;
So how to bind country to outside ItemsSource? The country is accessor in my "code behind" phoneApplicationPage.
It would be best that you make your models so that inside template you have to bind only to that item model.
Anyway it is possible to bind also outside of itemSource:
xaml:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<!-- this binds to the layoutRoot's dataContext, which can be setted to be "code behind" -->
<TextBlock Text="{Binding DataContext.Outside, ElementName=LayoutRoot}"/>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot">
<phone:LongListSelector ItemsSource="{Binding Items}"
IsGroupingEnabled="False"
ItemTemplate="{StaticResource ItemTemplate}">
</phone:LongListSelector>
</Grid>
In cs you have of course properties:
public ObservableCollection<Model> Items{get; set;}
public string Outside { get; set; }
Also layoutRoot's datacontext should be setted somewhere in cs:
LayoutRoot.DataContext = this;
I'm stuck again at some data-binding issue.
This time I want to bind a ListView to the SelectedItem of a GridView. I already suceed with this type of data-binding but now my ListView, which should show some details about my selected item in my GridView just stays empty. There are no items in it although they should exist.
The GridView binds just fine at the property in my MainViewModel.Substituting the ElementName attribute with x:Resouces doesn't seem to be an option, because it doesn't work either.
The source view:
<GridView x:Name="gridViewOrderYears"
ItemsSource="{Binding SelectedCustOrders, Mode=TwoWay}"
HorizontalAlignment="Left"
Grid.Row="1"
VerticalAlignment="Top"
Width="316"
Height="63"
Margin="657,316,0,0"
SelectionMode="Single">
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="1" BorderBrush="Aquamarine">
<StackPanel>
<TextBlock Text="{Binding Year}" FontSize="20"/>
<TextBlock Text="{Binding OrderCount}"/>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
this View doesnt bind:
<ListView HorizontalAlignment="Left"
Height="231"
Margin="657,401,0,0"
Grid.Row="1"
VerticalAlignment="Top"
Width="316"
DataContext="{Binding SelectedItem, ElementName=gridViewOrderYears}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DoneOrders.Order_Date, ElementName=gridViewOrderYears}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
SelectedCustOrders porperty is an IList<OrderYears>.
OrderYears is following data value object defined in my MainViewModel:
public class OrderYears
{
public int? Year { get; set; }
public IList<Orders> DoneOrders { get; set; }
public int OrderCount { get; set; }
}
I think the problem is in the ListView binding, because you try to bind to a property named "Orders", which does not exist in the OrderYears object. You have a property named DoneOrders which you can bind to (don't confuse the property name with the type of elements inside the list!), but if you bind a TextBlock to a IList you will just get the guid for the IList object.
Try something like this, replacing you ListView with a ListBox (which is enough for what you are trying to do here):
<ListBox DataContext="{Binding ElementName=gridViewOrderYears,
Path=SelectedItem.DoneOrders}"
DisplayMemberPath="Order_Date"/>
There is no need to create a template, the items inside the ListBox will be displayed like a TextBlock. Note that you can benefit from binding to nested properties like MainProperty.SubProperty.
Let me know if this was helpful, bindings can be such a headache when you are starting...
Finally I got it.
After hours of trial-and-error finally substituting DataContext with ItemsSource did the trick... Sometimes things are easier than you think :)