I'm working on Windows store app. Is there any way to programmatically create a listbox with datatemplate and then to bind data to datatemplate items?
I have created this listbox but now I need to create the same listbox programmatically because I need to create listboxes dynamically(count of listboxes is dynamic),
The second problem: I need to bind text to listbox datatemplate items. Does someone know something to recommend to me?
XAML:
<ListBox x:Name="lbTransitNow" ItemsSource="{Binding MyDataBusStationsCurrent}" SelectionChanged="LbTransitNow_OnSelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel>
<Grid x:Name="gridTodayBtn">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tbTransitStart" Grid.Column="0" Text="{Binding Lines_departure_date}" />
<TextBlock x:Name="tbTransitEnd" Grid.Column="1" Text="{Binding Lines_arrival_date}" />
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code:
foreach (var routs in cpStationsrs.RoutesList)
{
foreach (var lines in routs.LinesList)
{
foreach (var stops in lines.StopsList)
{
_myDataBusStationsChoosen.Add(new BindingData
{
Lines_stops_nameSub = stops.Name,
Lines_stops_timeSub = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, stops.Time.Hour, stops.Time.Minute, 0).ToString("dd.MM.yyyy -- HH:mm"),
Lines_nameSub = lines.Name,
...
});
}
}
}
OnPropertyChanged("MyDataBusStationsChoosen");
As far as I know, there is no way to create a DataTemplate programmatically in WinRT. However, if I understand your question correctly, you can reuse the same template for all listboxes... So you could just declare the template in the resources and reference it in each ListBox.
<Page.Resources>
<DataTemplate x:Key="myItemTemplate">
<StackPanel>
<Grid x:Name="gridTodayBtn">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="tbTransitStart" Grid.Column="0" Text="{Binding Lines_departure_date}" />
<TextBlock x:Name="tbTransitEnd" Grid.Column="1" Text="{Binding Lines_arrival_date}" />
</Grid>
</StackPanel>
</DataTemplate>
</Page.Resources>
Then, in code:
var listBox = new ListBox { ItemTemplate = (DataTemplate)Resources["myItemTemplate"] }
Related
Is there a way to make sure that the Width="auto" property considers the Width of all elements in a list instead of calculating it individually for every row in the list?
<ListBox x:Name="listBox" HorizontalContentAlignment="Stretch" DockPanel.Dock="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBlock Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I tried this, but as the length of the Name is different for each column, the Width of the Name column of every row is different. Thus the second column starts at a different x position.
You can use SharedSizeGroup property in the ColumnDefinition like this:
<ColumnDefinition SharedSizeGroup="A"/>
Also have a look at this: Grid Size Sharing in WPF.
the Xaml looks like this:
<ListBox Name="lbEurInsuredType" HorizontalContentAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<!-- <ColumnDefinition Width="20"></ColumnDefinition>-->
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}"></TextBlock>
<TextBox Text="{Binding Uw}"></TextBox>
<!-- <TextBox Text="{Binding Partner}"></TextBox>-->
</Grid>
</DataTemplate></ListBox.ItemTemplate>
</ListBox>
then in my code behind I have :
public DefaultSettings()
{
InitializeComponent();
List<EurItem> items = new List<EurItem>
{
new EurItem() { Title = "Couple", Uw = 190m, Partner = 170m },
new EurItem() { Title = "Family", Uw = 180m, Partner = 160m }
};
lbEurInsuredType.ItemsSource = items;
}
What happens is that If I Only have the TextBlock in the xaml, then the title shows in the listbox, as soon as I start to introduce other members, then it displays the last item that has been bound and looses all the others.
This is unnecessary because you are already directly setting it in your code behind.
ItemsSource="{Binding}"
Also, you are not setting any Grid.Column definitions on your succeeding elements. So they are overlapping each other.
You might want something like this
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}"></TextBlock>
<TextBox Text="{Binding Uw}" Grid.Column="1"></TextBox>
<TextBox Text="{Binding Partner}" Grid.Column="2"></TextBox>
</Grid>
You're placing several controls in a Grid with several columns. By default, each item you place inside a Grid is shown in the first row and first column.
Since you're not telling the controls otherwise, all your controls are being added to the first row and column, overlapping each other... So only the last control is shown.
You need to use Grid.Column to specify which column should each control be placed in.
<ListBox Name="lbEurInsuredType" HorizontalContentAlignment="Stretch" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition Width="30"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}"></TextBlock>
<TextBox Text="{Binding Uw}" Grid.Column="1"></TextBox>
<TextBox Text="{Binding Partner}" Grid.Column="2"></TextBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm new to the whole data binding thing with XAML for WP8.1. I've been searching on the internet and I can't seem to find a straight-forward answer to my problem.
I have a ListBox control on my page with 3 columns. What I need to do is fill each column with it's respective data.
I have a class that defines a "CompleteStation" which is made up of 3 strings (StationName, Distance, and GasPrice)
This is the XAML code for the ListBox... How am I able to pass the ListBox a CompleteStation (3 strings) and have it separate each string into the correct column?
This is my XAML code below. In my main class, I'm just adding a CommpleteStation item to the ListBox.
Also, do I need to reference the CompleteStation class in the XAML code? If yes, how do I do this?
<ListBox Name="listBoxStations" FontSize="20" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="480" Background="#e6e6e6" Margin="0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Station}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Distance}"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Price}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks!
-Johan
Lets say your CompleteStation is an ObservableCollection which implements NotifyPropertyChanged, Then XAML should be as follows
<ListBox Name="listBoxStations" ItemSource={Binding CompleteStation} FontSize="20" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="480" Background="#e6e6e6" Margin="0,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Station}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Distance}"/>
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Price}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Your Model:
public sealed class CommpleteStation
{
public string Station{get;set;}
public string Distance{get;set;}
public string Price{get;set;}
}
Your ViewModel:
public sealed class MyViewModel
{
public ObservableCollection<CommpleteStation> CommpleteStations{get;private set;}
public MyViewModel()
{
CommpleteStations = new ObservableCollection<CommpleteStation>();
CommpleteStations.Add(new CommpleteStation{Station="One", Distance="15",Price="130"};
}
}
Then,
IN codebehind for your UI, the "View", you instantiate your ViewModel and set it as the DataContext for your View.
public MyView()
{
this.DataContext = new MyViewModel();
}
I have gone through msdn article "Accessing contact and calendar data for Windows Phone"
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh286414(v=vs.105).aspx#BKMK_CreatingtheApplicationProject
<TextBlock Text="phone numbers" Margin="12,12,0,0"/>
<ListBox ItemsSource="{Binding Path=PhoneNumbers}" Height="60" Margin="36,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Path=Kind, Mode=OneWay}" />
<TextBlock Grid.Column="1" Text=": " />
<TextBlock x:Name="pno" Grid.Column="2" Text="{Binding Path=PhoneNumber, Mode=OneWay}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In the above XAML Phone Number is dynamic bound to the TextBlock Name="pno"(Named myself not in msdn code)
I want to get the Phone number in a variable say Phone_no .How ????
Don't bind to the default ContactPhoneNumber (don't use the IEnumerable called PhoneNumbers for binding).
Create your own class to hold phone number data
public class MyContactPhoneNumber
{
public PhoneNumber Phone_no {get; set;}
//other properties you want
}
and create a new collection of those custom contact phone numbers
List<MyContactPhoneNumber> myNumbers = new List<MyContactPhoneNumber>();
Then in a foreach loop copy data from PhoneNumbers to a list of MyContactPhoneNumber
foreach (var number in PhoneNumbers)
myNumbers.Add(new MyContactPhoneNumber
{
//...copy all properties here, for example Phone_no = number.PhoneNumber
});
And then bind that to the UI
ListOfNumbers.ItemsSource = myNumbers;
// and in XAML
<ListBox Name="ListOfNumbers" Height="60" Margin="36,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="pno" Text="{Binding Path=Phone_no, Mode=OneWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you want two way binding support and better binding support overall, use ObservableCollection instead of a List and implement INotifyPropertyChanged in MyContactPhoneNumber class.
I gave up on my code bugs so I decide to write here. I really hope to get a solution. What I want with the listbox is: when i click the button, it will retrieve data from database then load it into the listbox. It worked fine. But when I add wpf style, it started problem because I want to add image into each item next to text - image (right side) and text (left side). The result in the listbox is blank but actually it seems there is a data list - please look at the picture. I may have done something wrong in my code or wpf. I am not sure what is problem.... I would appreciate if you can have a look at my code. Your given code would be much helpful. Thanks alot!
WPF:
<ListBox Name="lstDinner" DisplayMemberPath="Name" Margin="513,85,608,445" Style="{DynamicResource ResourceKey=styleListBox}"/>
WPF STYLE:
<DataTemplate x:Key="templateListBoxItem">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
Margin="0,0,10,0">
<Image Source="{Binding Path=Image}"
Stretch="Fill"
Height="40"
Width="40"></Image>
</Border>
<TextBlock Text="{Binding Path=Name}"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="0"></TextBlock>
<TextBlock Text="{Binding Path=About}"
Grid.Column="1"
Grid.Row="1"></TextBlock>
</Grid>
</DataTemplate>
<Style x:Key="styleListBox" TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate" Value="{StaticResource ResourceKey=templateListBoxItem}"></Setter>
</Style>
C#:
private void Button_Click(object sender, RoutedEventArgs e)
{
_dinnerExtractor = new DinnerExtractor();
const int oneDay = 1;
_databaseDinnerList = new ObservableCollection<FoodInformation>(_dinnerExtractor.GetDinnerDays(oneDay));
if (_databaseDinnerList != null)
{
foreach (var list in _databaseDinnerList)
{
lstDinner.Items.Add(new FoodInformation { Dinner = list.Dinner, DinnerImage = list.DinnerImage});
}
//lstDinner.ItemsSource = _databaseDinnerList;
}
}
FoodInformation class does not contains properties: Image and Name (you are trying binding to these properties in DataTemplate).
From code-behind we can create definition of FoodInformation class with properties Dinner and DinnerImage:
class FoodInformation
{
public string Dinner { get; set; }
public ImageSource DinnerImage { get; set; }
}
So you should binding to properties Dinner and DinnerImage, not to Image and Name.
If you change in DataTemplate appropriate properties names everything will be ok.
<DataTemplate x:Key="templateListBoxItem">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
Margin="0,0,10,0">
<Image Source="{Binding Path=DinnerImage }"
Stretch="Fill"
Height="40"
Width="40"></Image>
</Border>
<TextBlock Text="{Binding Path=Dinner }"
FontWeight="Bold"
Grid.Column="1"
Grid.Row="0"></TextBlock>
</Grid>
</DataTemplate>