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 :)
Related
Let me explain so I have a wpf application I used a listBox with a template. This template contains a TextBlock and a ComboBox. When running the application, everything goes well, my list is initialized correctly. But then I would like to retrieve the values of my TextBlock and my comboBox and I don't understand how I can achieve this.
I am attaching the part of my XAML code that deals with this listBox :
<ListBox x:Name="ListBoxEnv" Grid.Row="1"
d:ItemsSource="{d:SampleData ItemCount=5}" Width="460"
SelectionChanged="ListBoxEnv_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TxtBlockEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
Text="{Binding EnvName}"/>
<ComboBox x:Name="ComboBoxEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding EnvListValue}"
Margin="100,2,0,2" Width="200"
SelectionChanged="ComboBoxEnv_SelectionChanged"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The EnvName property is readonly because it is bound to TextBlock, so you can ignore it. Change binding to: Text="{Binding EnvName, Mode=OneTime}" to save the app resources.
However to extract selected environment in every combo in the list you need to add to ComboBox template: SelectedItem={Binding SelectedEnv} and add new property to SampleData
for example
public MyEnvironmentClass SelectedEnv {get; set;}
I have a ListBox that displays a List<Item> Items with Item being a custom object. Foreach item I want the user to see a ComboBox with List<string> Options as the Source with the selected Item tying back to a property on a Item . In the list box I have no trouble binding the individual Item properties but how do I reach back up into the DataContext to get my list of options?
View Model is being set as the page's DataContext
class ViewModel
{
public ObservableCollection<string> Options { get; set; }
public ObservableCollection<Item> Items { get; set; }
}
Xaml
<ListBox x:Name="ItemsListBox" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="50" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="ItemProperty1TB"
Text="{Binding Path=Property1, Mode=OneWay}"
Grid.Column="0"
/>
<ComboBox x:Name="OptionsCB"
SelectedItem ="{Binding ChosenOptions, Mode=TwoWay}"
ItemsSource="{Binding Path=DataContext.Options}"
Grid.Column="1"
PlaceholderText="Option"
/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried to cut out as much extra code and get to a readable example.
How to bind to a source inside a ListBox different from the ItemsSource already specified This uses AncestorType that does not exist?
ComboBox inside Listbox.ItemTemplate Binding problem This binds to a static resource. Should I put my options into a static resource?
ElementName looks promising but my IDE only recommends Elements scoped to inside the ListBox... DO NOT TRUST VISUAL STUDIO
Am I just going about this all wrong?
Try this:
ItemsSource="{Binding Path=DataContext.Options, ElementName=ItemsListBox}"
You can use RelativeSource property on Combobox binding object to find the parent. Something like this should work
ItemsSource="{Binding Path=DataContext.Options, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
Replace UserControl with Page if you are using Page or Window for that matter.
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.
I am using WPF + MVVM.
If I have a ComboBox, normally the names listed in the Dropdown are is defined by the .ToString() overload on the contents of the ObservableCollection.
Is there a way to control the names in the Dropdown list using XAML instead of the .ToString() overload?
What I have tried
I've spent a lot of time on this. The only solution I have come up with so far is to inherit from the original class, and define a new .ToString() override, but this solution is ugly, ugly, ugly.
You need to override the ItemTemplate.
E.g.
<ComboBox ItemsSource="{Binding MyItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Name}" Width="16" Height="16" Margin="0,2,5,2" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Or what you can do if you only want to display a specific field, is to use DisplayMemberPath
e.g.
<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
SelectedValue="{Binding Path=PhonebookEntry}" />
You are binding to an ObservableCollection<T>. If you don't tell the binding engine what property to bind to in T, it will call .ToString() on the T class and place the results in a TextBlock.
Let's say you have a class, Trip
public class Trip
{
public string TripName { get; set; }
public string Description { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
To show the TripName in ComboBox, use a DataTemplate (as suggested by Michal). This allows you to specify what type of elements are used to render the bound data and what properties to bind to.
<ComboBox ItemsSource="{Binding Trips}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TripName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
To bind to a different property use another property name:
<TextBlock Text="{Binding Description }" />
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;