When a Windows Phone 7 application opens a view, a certain order of business is followed in order to create. As far as constructors and events go, I have found this order to be true:
ConstructorOnNavigatedToOnLoaded
However, I am in a position where I need to databind a List to a ListBox after the basic view (background, other elements etc) has loaded. So I need to know when and how to know that the view is loaded before I get on with the data binding.
I have tried to do this on the OnLoaded-event, but it seems like if I do the data binding here – and right after it traverse those elements – they don’t seem to exist yet (the VisualTreeHelper-class can’t seem to find the nodes). So as you see, I am stuck.
Any help would be greatly appreciated.
Edit: As requested, here is some more information about what’s going on.
My List is populated by some custom (not too complicated) objects, including an asynchronously loaded image (courtesy of delay.LowProfileImageLoader) and a rectangle.
The XAML:
<ListBox x:Name="ChannelsListBox" ItemsSource="{Binding AllChannels}">
//...
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="ChannelTile" Margin="6,6,6,6" Tap="ChannelTile_Tap" Opacity="0.4">
<!-- context menu goes here -->
<Rectangle Width="136" Height="136" Fill="{StaticResource LightGrayColor}" />
<Image Width="136" Height="136" delay:LowProfileImageLoader.UriSource="{Binding ImageUri}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code-behind:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
UpdateApplicationBar();
pickChannelsViewModel = new PickChannelsViewModel();
DataContext = pickChannelsViewModel;
if (hasUpdatedTiles)
{
pickChannelsViewModel.IsLoading = false; // Set by UpdateTiles()
}
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
// This is where I would data bind the list (instead of in XAML)
UpdateTiles(); // Traverses the list and changes opacity of "selected" items.
}
protected void UpdateTiles()
{
foreach (var item in ChannelsListBox.Items)
{
if (pickChannelsViewModel.SelectedChannels.Contains(item as Channel))
{
var index = ChannelsListBox.Items.IndexOf(item);
// This returns null when databinding in codebehind,
// but not in XAML
ListBoxItem currentItem = ChannelsListBox.ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
if (currentItem != null && VisualTreeHelper.GetChildrenCount(currentItem) == 1)
{
var OuterWrapper = VisualTreeHelper.GetChild(currentItem, 0);
var MiddleWrapper = VisualTreeHelper.GetChild(OuterWrapper, 0);
var InnerWrapper = VisualTreeHelper.GetChild(MiddleWrapper, 0);
Grid currentItemGrid = VisualTreeHelper.GetChild(InnerWrapper, 0) as Grid;
currentItemGrid.Opacity = 1.0;
}
}
}
pickChannelsViewModel.IsLoading = false;
hasUpdatedTiles = true;
}
The items themselves are in-memory (fetched from REST at an earlier stage in the application), so should be available instantaneously.
The issue I am trying to resolve is a fairly long load time on this particularly view (there is about 140 of these items being created, then filtered through and changing the opacity).
I believe you are doing something like:
Once you set the ItemSource of a ListBox the changes in your List should be reflected in the ListBox at all times. If the ListBox is empty the reason must be that the List is not being populated properly or invalid
Bindingsin the ItemTemplate. You should debug and find out if your List has any items by inserting a breakpoint in theLoaded()method. Also, you’ve not mentioned what items does your List contains or, where is it being populated in the application? Incomplete information doesn’t help anyone.