开发者

ListBox Binding with Global Index

My application has a couple of ObservableCollections, one which is nested within an element of the other. Each contain a number of fields e.g.

ObservableC开发者_高级运维ollectionA (called Listings)

  • Title
  • Description
  • Address
  • Images As MediaItems

ObservableCollectionB (called MediaItems)

  • ImageName
  • Src
  • DisplayTime

Currently I have been accessing ObservableCollections as follows:

Listings(0).MediaItems(0).ImageName

My application has the main Window display the items from Listings and a UserControl which contains a ListBox which displays the items from MediaItems.

Currently my Window is bound to Listings using code in the New method:

Dim AppLocal As Program = Application.CurrentItem
AppLocal.CurrentItem = 0
Me.DataContext = Listings.Item(AppLocal.CurrentItem)

For the Listings ObservableCollection, the UserControl has a XAML DataContext which references a local method which pulls the records from the nested MediaItems ObservableCollection.

<UserControl.DataContext>
    <ObjectDataProvider ObjectType="{x:Type local:ThumbImageLoader}" MethodName="LoadImagesv2" IsAsynchronous="True"  />
</UserControl.DataContext>
<Grid x:Name="ThumbListBoxGrid">
    <ListBox x:Name="ThumbListBox" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" />
</Grid>

The method is here:

Public NotInheritable Class ThumbImageLoader
Public Shared Function LoadImagesv2() As List(Of MediaItems)

    Dim AppLocal As Program = Application.Current

    Dim ThumbImages As New List(Of MediaItems)

    ThumbImages = Listings(AppLocal.CurrentItem).MediaItems

    Return ThumbImages
End Function
End Class

Whilst developing the UI layout I have just been binding the first item (0 index). I now want to be able to set AppLocal.CurrentItem from anywhere in the application so the Window and the ListBox are updated.

Ideally I would like it so when the global property index changes, the UI is updated.

How do I do this?

Is there a better way to go about it?

Ben


Ok, I discovered the joy of CollectionView. Offered exactly what I was after and was excrutiatingly easy to implement. I was blown away at not only how easy it was to implement, but I managed to cut out more lines of code than I used to implement it.

I implemented a public CollectionViewSource

Public ListingDataView As CollectionViewSource

In my main Window, I implemeted it as follows:

<CollectionViewSource x:Key="ListingDataView" />

and bound my top-level Grid to it:

<Grid DataContext="{Binding Source={StaticResource ListingDataView}}">

In my Application Startup I set the CollectionView Source

AppLocal.ListingDataView = CType(Application.Current.MainWindow.Resources("ListingDataView"), CollectionViewSource)
AppLocal.ListingDataView.Source = Listings

The next part which impressed me the most was implementing it for my User Control. I remembered the UserControl is inheriting from the main window so it has access to the CollectionView already, so I ditched the separate Class and Method binding in favour for this:

<ListBox ItemsSource="{Binding Path=MediaItems}" VerticalAlignment="Top" IsSynchronizedWithCurrentItem="True" />

Now whene I want to set the Current List Index, I simply call this:

AppLocal.ListingDataView.View.MoveCurrentToPosition(AppLocal.CurrentProperty)

A few milliseconds later, the UI updates automatically.

Done!!


When you want multiple source data (like your observable collection properties and the index for the observable collection) to a single target you should use MultiBinding.

So in your case somethign like this should help...

<ListBox x:Name="ThumbListBox" IsSynchronizedWithCurrentItem="True" >
   <ListBox.ItemsSource>
      <MultiBinding Converter="{StaticResource CollectionAndIndexCollaborator}">
           <Binding Path="Listings" />
           <Binding Path="Application.CurrentItem.CurrentItem" />
      </MultiBinding> 
   </ListBox.ItemsSource>
</ListBox>

provided that ....

  1. Your data context is some class that holds the Application object via a property of same name Application and the Listings collection via property of same name Listings.
  2. Your DataContext class and Application class must have INotifyPropertyChanged implemented. It should also raise notifications for Application and Setter of CurrentItem and CurrentItem.CurrentItem properties.
  3. CollectionAndIndexCollaborator.Convert() method returns the same indexed value as the final collection....

    return ((ObservableCollection)values[0]).Item(int.Parse(values[1])) ;

where assuming MyListingType is the T of your Listings collection.

This way when anyone changes the global Application.CurrentItem.CurrentItem the multi binding above will get notified and will select the required Listings item.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜