|
-
Mar 24th, 2011, 06:11 PM
#1
Binding ComboBox to an extension method in a different Window - not updating
Hi,
I am using AvalonDock to create a nice UI for my playlist manager. Basically it is an app that allows me to view playlists side by side, drag songs from one to another, and search through multiple playlists at the same time.
In my search window I now want to be able to choose which playlist windows to search through. By default they will all be chosen, but I might not want to search a certain playlist and should then be able to exclude that.
So my idea was to use a ComboBox, where each item is a CheckBox. When checked, the search includes that playlist, so I can simply dropdown the ComboBox and uncheck the playlists I do not want to search in.
The SearchWindow has a reference to the main window (that hosts the playlist windows), and the MainWindow has a PlaylistWindows property that returns the Documents of type PlaylistWindow (so that it excludes things like toolwindows).
In the constructor of the MainWindow I immediately create the SearchWindow (but just hide it until I need it), passing the MainWindow instance along. That gives us:
vb.net Code:
Class MainWindow
Private searchWindow As SearchWindow
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
searchWindow = New SearchWindow(Me)
searchWindow.Name = "searchWindow"
searchWindow.HideOnClose = True
searchPane.Items.Add(searchWindow)
searchWindow.Hide()
End Sub
Public ReadOnly Property PlaylistWindows As IEnumerable(Of PlaylistWindow)
Get
Return Me.dockingManager.Documents.OfType(Of PlaylistWindow)()
End Get
End Property
'...
End Class
I thought I would now be able to bind the ComboBox to the PlaylistWindows property of the MainWindow reference, so that's what I did:
vb.net Code:
Public Class SearchWindow
Private _MainWindow As MainWindow
Public Sub New(ByVal mainWindow As MainWindow)
Me.InitializeComponent()
_MainWindow = mainWindow
playlists.ItemsSource = _MainWindow.PlaylistWindows
End Sub
(playlists is the ComboBox)
In XAML I defined an ItemTemplate for the ComboBox so that it displays a CheckBox as well as the number of songs in the playlist:
Code:
<ComboBox Name="playlists" Margin="5">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Content="{Binding Title}" />
<Label Grid.Column="1" FontSize="10">
<Binding Path="Playlist.Count" StringFormat="Songs: {0}" />
</Label>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
When I now run this, however many playlist windows I open, the ComboBox never displays any. It always has 0 items.
I think I know what the problem is, I just don't know how to fix it. I guess the problem is that the SearchWindow is created before any PlaylistWindows are created. So the binding is initiated with 0 playlist windows and simply never updated.
Is the problem that 'MainWindow.PlaylistWindows' is not a dependency property and thus does automatically update? If so, is there anything I can do about that? I am simply returning the OfType extension method of the Documents property of the AvalonDock dock manager. If that property is not a dependecy property then I don't think I can do anything about it, can I..??
I also tried it the 'old fashioned way' by simply re-binding the ComboBox before it opens, but there does not seem to be any event that is raised before the dropdown opens, so I'm not sure if I can do that either...
Thanks!
-
Mar 24th, 2011, 06:24 PM
#2
Re: Binding ComboBox to an extension method in a different Window - not updating
Your PlaylistWindow property needs to return an object that implements INotifyCollectionChanged (note that it need not be typed as such. The property can still return an IEnumerable, but the object that is returned must also implement INotifyCollectionChanged.
As you add and remove windows from MainWindow, they must be added and removed from the collection that you the PlaylistWindow property is a reference to. As that happens, the collection will fire the CollectionChanged event (from the INotifyCollectionChanged interface) and WPF will update anything bound to that collection.
The simplest way to do this, I would imagine, is to maintain an ObservableCollection in your MainWindow that you keep in sync with the DockingManager. This is the object that should be given out by the PlaylistWindow property.
-
Mar 24th, 2011, 08:12 PM
#3
Re: Binding ComboBox to an extension method in a different Window - not updating
I thought I'd need to implement INotifyPropertyChanged, but since I'm returning dockingManager.Documents.OfType(Of T) directly I am kind of dependent on that... I don't think even the Documents collection implements INotifyPropertyChanged (it is some kind of custom collection from the docking suite), and even if it did that wouldn't help since I'm returning the OfType extension method, right (or would that 'carry over' ?)
So I guess my only option then is to indeed have a separate property that I have to keep in sync with the Documents property. That's not ideal. As far as I can see the type of the Documents property doesn't even raise any events so I cannot detect directly when the collection changes. I can always sync the properties when I add or close a document but I'm not sure if I can keep them synced in all conditions that way... In any case, I thought WPF was all about doing this kind of thing for you using data binding. Keeping two collections in sync seems to be something that you'd need to do in winforms but not anymore in WPF... Too bad. I guess it's the fault of the DockingManager right? I'm going to see if I can just get the source instead and make the Documents property collection raise an event, that would make my life easier...
Anyway, thanks for the explanation.
-
Mar 24th, 2011, 08:35 PM
#4
Re: Binding ComboBox to an extension method in a different Window - not updating
 Originally Posted by NickThissen
...INotifyPropertyChanged...
You did note that I said INotifyCollectionChanged, didn't you?
And yes, WPF will handle this stuff for you, as long as the underlying collections support some way of telling WPF about changes, hence the INotifyProperty/CollectionChanged interfaces.
-
Mar 24th, 2011, 09:00 PM
#5
Re: Binding ComboBox to an extension method in a different Window - not updating
Yeah, that's what I meant sorry.
Anyway, I downloaded the source for AvalonDock and figured out that the ManagedContentCollection(Of T) class (the type of the Documents property) actually inherits ReadOnlyObservableCollection(Of T). So it does raise the collection changed event, it's just that the event is Protected so I couldn't see it.
However, I can simply cast it to INotifyCollectionChanged and then attach the event handler anyway So that's what I did.
vb.net Code:
Dim documentsCollection = DirectCast(dockingManager.Documents, INotifyCollectionChanged) AddHandler documentsCollection.CollectionChanged, AddressOf DockingManager_DocumentsCollectionChanged
Then I created a dependency property that I set to Documents.OfType(Of PlaylistWindow) every time the Documents collection changes, and I bind to that dependency property. I would think that would allow WPF to automatically pick up on the changes, but apparently it still doesn't... The ComboBox still stays empty.
vb.net Code:
Public Property PlaylistWindows As IEnumerable(Of PlaylistWindow) Get Return Me.GetValue(PlaylistWindowsProperty) End Get Private Set(ByVal value As IEnumerable(Of PlaylistWindow)) Me.SetValue(PlaylistWindowsProperty, value) End Set End Property Public Shared ReadOnly PlaylistWindowsProperty As DependencyProperty = DependencyProperty.Register("PlaylistWindows", GetType(IEnumerable(Of PlaylistWindow)), GetType(MainWindow)) Private Sub DockingManager_DocumentsCollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs) Me.PlaylistWindows = dockingManager.Documents.OfType(Of PlaylistWindow)() End Sub
So in the end I resorted to letting my MainWindow raise another event which the Searchwindow can then handle. This way I finally got the windows in the ComboBox 
I supposed I could have put the PlaylistWindows in an ObservableCollection(Of PlaylistWindow) instead (that should work, right?), but it works now so I'm good.
I still don't see why the dependency property doesn't work though. I must be misunderstanding their use... I've read about them but it's been a few months and I haven't really used them yet.
Now I just need to get the ComboBox to display the items properly. Whenever I select an item now the entire ComboBox morhps into a Playlist Window haha! Interesting, but that wasn't supposed to happen
-
Mar 24th, 2011, 10:10 PM
#6
Re: Binding ComboBox to an extension method in a different Window - not updating
Perhaps it would be better to expose the Documents property, and apply a filter to the collection view in the Search Window. Grab the default View of the collection from the ItemsSource and there should be a Filter property in there that you can fritz with.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|