I am attmepting to bind an ObservableCollection of items to a ListPicker from the Silverlight toolkit for Windows Phone. I have done this before, but in my case now, my ObservableCollection contains items from a custom class. I do not know how to get each of the properties of the class (for each item) to bind to my ListPicker. To better illustrate what I have is as follows:
MainPage.xaml
<Grid.Resources>
<DataTemplate x:Name="SearchProviderItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Favicon}" />
<TextBlock Text="{Binding Name}" Margin="12,0,0,0"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="SearchProviderFullModeItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Favicon}" />
<TextBlock Text="{Binding Name}" Margin="12,0,0,0"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<toolkit:ListPicker x:Name="SearchProviderListPicker" ItemsSource="{Binding SearchProvider}" Margin="12,0,12,0"
Header="Search provider" ItemTemplate="{Binding SearchProviderItemTemplate}"
FullModeHeader="Search provider" FullModeItemTemplate="{Binding SearchProviderFullModeItemTemplate}"
SelectedIndex="{Binding}"
SelectionChanged="SearchProviderListPicker_SelectionChanged"
CacheMode="BitmapCache"/>
MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
//This data is placed here for convenience right now
ListItem Bing = new ListItem { Favicon = "", Name = "Bing", Address = "http://www.bing.com/search?q=" };
ListItem Google = new ListItem { Favicon = "", Name = "Google", Address = "http://www.google.com/search?q=" };
ListItem Yahoo = new ListItem { Favicon = "", Name = "Yahoo", Address = "http://search.yahoo.com/search?p=" };
ListItem Ask = new ListItem { Favicon = "", Name = "Ask", Address = "http://www.ask.com/web?q=" };
ListItem Aol = new ListItem { Favicon = "", Name = "AOL", Address = "http://search.aol.com/search?q=" };
Settings.SearchProvider.Value.Add(Bing);
Settings.SearchProvider.Value.Add(Google);
Settings.SearchProvider.Value.Add(Yahoo);
Settings.SearchProvider.Value.Add(Ask);
Settings.SearchProvider.Value.Add(Aol);
// Set the data context of the SearchProviderListPicker control to the data
DataContext = App.ViewModel;
}
MainViewModel.cs
public ObservableCollection<ListItem> SearchProvider { get; private set; }
public MainViewModel()
{
SearchProvider = Settings.SearchProvider.Value;
}
The Settings class referenced above is used to store the SearchProvider ObservableCollection in isolated storage.
Settings.cs
public static Setting<ObservableCollection<ListItem>> SearchProvider = new Setting<ObservableCollection<ListItem>>("SearchProvider", new ObservableCollection<ListItem>());
And the Setting class saves and gets the data from isolated storage.
Also, my custom ListItem class demonstrates the properties I need to use.
ListItem.cs
public string Favicon
{
get;
set;
}
public string Name
{
get;
set;
}
public string Address
{
get;
set;
}
So basically each SearchProvider ObservableCollection item contains the Favicon, Name, and Address that I need to use, and I only want to bind the Favicon and Name to the ListPicker. My problem though, is the ListPicker presents the 5 search providers except the text for each says Project1.Common.ListItem where the ListItem class in in my Common folder. I must not be binding these correctly to the view, but I do not know how to properly accomplish this?
Your ListPicker's templates are Static resources defined in Grid.Resources
Hence you have to change the ListPicker xaml code like the this
ItemTemplate="{Binding SearchProviderItemTemplate}"
FullModeItemTemplate="{Binding SearchProviderFullModeItemTemplate}"
replace the above two properties to the following
ItemTemplate="{StaticResource SearchProviderItemTemplate}"
FullModeItemTemplate="{StaticResource SearchProviderFullModeItemTemplate}"
If you are getting 'Project1.Common.ListItem' as the text that means your binding is correct but there is a problem with your template.
The first correction is as given above, you need to use "StaticResource" instead of "Binding" when you are referring to templates.
Please recheck your template for any typos etc.
If i were you, i would first try to make it work without using the Settings class, See if that helps
Related
I have a class defined like:
public class Agent
{
public int Id { get; set; }
public string Category { get; set; }
// rest removed for brevity
}
Then, in WPF, I get the data as List and pass it to DataContext as this:
List<Agent> agents; // this includes my data
this.DataContext = agents;
And in .xaml part I want to list the Category field of each object. I have something like this:
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=Category"} />
But this doesn't seem to work correctly. Any ideas?
Let me help you to do this in the correct way as Alex suggested.
Create a list and populate it in ViewModel like this
ViewModel
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
agents = new ObservableCollection<Agent>();
LoadData();
}
private void LoadData()
{
agents.Add(new Agent { Id = 1, Category = "a" });
agents.Add(new Agent { Id = 2, Category = "b" });
agents.Add(new Agent { Id = 3, Category = "c" });
}
}
In XAML, Make your list and use data template like this:
<Window.Resources>
<DataTemplate x:Key="AItemTemplate">
<TextBlock Text="{Binding Category}"></TextBlock>
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding agents}"
ItemTemplate="{StaticResource AItemTemplate}"></ListBox>
That is it !!
Normally the DataContext would be a view model class that would contain the list of agents; then you can bind the ItemsSource to that list. Any of the many examples that deal with listbox will be pretty straight forward when it comes to that. Not really sure how the binding should look like if the list itself is the DataContext.
Then once the ItemsSource is set to a list of agents, if you want to show the Category in the list, the simpler way is to set DisplayMemberPath to "Category".
I suggest looking into MVVM and learning to apply it, it's an invaluable concept in my opinion.
You try to bind your listbox to a string property.
You can try this :
Give a name to your user control for exemle myUC
Add a property to your user control :
public List<Agent> AgentList { get; set; };
Fill your agentlist :
this.AgentList = //fill method
And bind your listbox like this :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
Grid.Column="1"
ItemSource="{Binding Path=AgentList, ElementName=myUC"} />
may be this will give you an idea:
http://www.c-sharpcorner.com/forums/wpf-datacontext-binding-with-listbox
The fastest way to get what you want is :
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=."} />
ItemsSource is binded directly to your Datacontext (which is your list) And then you tell to your ListBox to display the property Category.
But the proper way would have been :
1 - Create a DataContext
public class AgentsDC
{
public List<Agent> Agents { get; set; }
}
2 - Give this class as DataContext
this.DataContext = new AgentsDC();
3 - Bind all these things
<ListBox
Name="agentCategoryListBox"
Grid.Row="2"
DisplayMemberPath="Category"
Grid.Column="1"
ItemSource="{Binding Path=Agents"} />
I also would suggest you to use MVVM. But if you do not want to then try this.
XAML:
<ListBox Name="AgentCategoryListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}" d:DataContext="{d:DesignData}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
CS:
public MainWindow()
{
InitializeComponent();
List<Agent> agents = new List<Agent>
{
new Agent
{
Category = "Category"
}
};
DataContext = agents;
}
public class Agent
{
public string Category
{
get;
set;
}
}
I have an ItemsControl used to display View of items like this:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding View}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Below is short mcve to give you an idea:
public class Item
{
public string Text { get; set; }
public object View { get; set; }
... // more properties used in bindings
}
public partial class MainWindow : Window
{
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
public MainWindow()
{
InitializeComponent();
// 1
{
var control = new TextBlock();
var item = new Item { Text = "1", View = control };
BindingOperations.SetBinding(control, TextBlock.TextProperty, new Binding(nameof(Item.Text)) { Source = item });
Items.Add(item);
}
// 2
{
var control = new CheckBox();
var item = new Item { Text = "2", View = control };
BindingOperations.SetBinding(control, CheckBox.ContentProperty, new Binding(nameof(Item.Text)) { Source = item });
Items.Add(item);
}
// ... and so on
DataContext = this;
}
}
As you can see each item has pre-created View (unfortunately this can't/shouldn't be changed), which can be anything, includes binding, etc.
My question: how to move creating of View into xaml (as data templates)?
Pseudoxaml:
<SomeContainer.Resources>
<DataTemplate x:Key="type1">
<TextBlock Text="{Binding Text}" />
</DataTemplate>
<DataTemplate x:Key="type2">
<CheckBox Content="{Binding Text}" />
</DataTemplate>
</SomeContainer.Resources>
<ItemsControl ... /> <!-- same definition as early? -->
Pseudo-code
Items.Add(new Item { Text = "1", View = LoadTemplate("type1") });
Items.Add(new Item { Text = "2", View = LoadTemplate("type2") });
object LoadTemplate(string key)
{
var resource = FindResource(key);
... // what next?
}
if you absolutely have to use UIElements in view model (instead of templates), and at the same time want to declare them in xaml, then
don't use DataTemplate
use x:Shared="False" on UIElement
<Window.Resources>
<TextBlock x:Key="type1" x:Shared="False" Text="{Binding Text}"/>
<CheckBox x:Key="type2" x:Shared="False" Content="{Binding Text}"/>
</Window.Resources>
each time you request a resource, you will get a new copy
LoadTemplate method is reduced to FindResource
object LoadTemplate(string key)
{
return FindResource(key);
}
Instead of creating a UI control such as a TextBlock or a CheckBox in the view model you should create a CLR object:
public class MyTextClass
{
public string Text { get; set; }
}
...
var view = new MyTextClass();
var item = new Item { Text = "1", View = control };
You could then use a DataTemplate in the view to associate an instance of your CLR object with a control:
<DataTemplate DataType="local:MyTextClass">
<TextBlock Text="{Binding Text}" />
</DataTemplate>
When you set the DataType property of a DataTemplate without specifying an x:Key, the DataTemplate gets applied automatically to data objects of that type: https://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype(v=vs.110).aspx
I am fairly new to working with WPF and have this simple scenario which I am looking to implement:
I have two comboboxes, cmbSite and cmbLogFiles and I have a List<LogFileDirectory> which is defined as follows:
class LogFileDirectory
{
public List<System.IO.FileInfo> Files { get; private set; }
public string Name { get; private set; }
public string Path { get; private set; }
private LogFileDirectory() { }
public LogFileDirectory(string name, string path)
{
this.Name = name;
this.Path = path;
this.Files = new List<System.IO.FileInfo>();
if (System.IO.Directory.Exists(this.Path))
{
foreach (string file in System.IO.Directory.GetFiles(this.Path, "*.log", System.IO.SearchOption.TopDirectoryOnly))
this.Files.Add(new System.IO.FileInfo(file));
}
}
}
I have cmbSite bound to the Name property on the List<LogFileDirectory> in the code behind like this:
cmbSite.ItemsSource = _logFileInfo.WebServerLogFileDirectories;
cmbSite.SelectedValue = "Path";
cmbSite.DisplayMemberPath = "Name";
I would like cmbLogFiles bound to the Files property on the same List<LogFileDirectory> of the currently selected cmbSite and filtered to the entry LogFileDirectory object for the currently selected value of cmbSite, but I am really not quite sure how to do this without writing code in the ClickEvent handler of cmbSite (which seems like the wrong approach based on my WPF research) and rebinding cmbLogFiles to the select cmbSite LogFileDirectory.
Based on the thread that #Chris pointed me to in the comment above, the resolution was simple.
<ComboBox Name="cmbLogFiles" Width="140" ItemsSource="{Binding SelectedItem.Files, ElementName=cmbSite}" />
Where the ItemsSource property of cmbLogFiles specifies that the Binding will be the Files Property off of the SelectedItem object (which is defined as object of LogFileDirectory) and specified via the Element attribute to my other combobox (cmbSites).
I was able to remove all of the code behind by setting a DataContext on my window:
parserView = new Parser();
parserView.DataContext = new LogFileInfo("deathstar");
And then the subsequent XAML of the Parser window:
<Window x:Class="Zapora.UI.Parser"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Log File Parser" Height="350" Width="525">
<StackPanel Orientation="Horizontal" Height="26" VerticalAlignment="Top">
<Label Content="Web Site:"/>
<ComboBox Name="cmbSite" Width="180" ItemsSource="{Binding WebServerLogFileDirectories}" DisplayMemberPath="Name" SelectedValuePath="Path"/>
<Label Content="Files Available:"/>
<ComboBox Name="cmbLogFiles" Width="140" ItemsSource="{Binding SelectedItem.Files, ElementName=cmbSite}" />
</StackPanel>
</Window>
Im trying to supply a data template to my ribbon.
The ribbon is declared as following, and has an ItemTemplate attached to it.
<r:Ribbon Name="RibbonMain"
ItemTemplate="{StaticResource HomeRibbonTabTemplate}">
</r:Ribbon>
The Datatemplate is the following:
<Window.Resources>
<DataTemplate DataType="{x:Type local:RibbonContainer}"
x:Key="HomeRibbonTabTemplate">
<r:RibbonTab Header="{Binding Path=HeaderName}">
<r:RibbonGroup Header="{Binding Path=GroupName}">
</r:RibbonGroup>
</r:RibbonTab>
</DataTemplate>
</Window.Resources>
I do then attach the ItemsSource:
public MainWindow()
{
InitializeComponent();
var RibbonTabData = new ObservableCollection<RibbonContainer>();
RibbonTabData.Add(new RibbonContainer("HeaderName", "GroupName"));
RibbonMain.ItemsSource = RibbonTabData;
}
Lastly the class: (Which just contains two string fields)
class RibbonContainer
{
public string HeaderName
{
get;
set;
}
public string GroupName
{
get;
set;
}
public RibbonContainer(string _headername, string _groupname)
{
HeaderName = _headername;
GroupName = _groupname;
}
}
I get the unimpressive result of showing the fully qualified class name in the tab header and neither is the ribbongroup showing. (This is what the datatemplate should solve?)
What to do?
Best regards
I'm not exactly sure where to start, but perhaps with a short warning that, in trying to create a RibbonControl totally from data Binding and data items, you really are opening up a huge can of whoop ass on yourself. This is because the developers that designed the code for it used unconventional patterns for some of it and failed to adequately document how to do things with it. Some of the best sources will be found by searching on this website.
So anyway, if you're up for a painful, uphill struggle, read on. Your first mistake was trying to use a DataTemplate for the RibbonTab because it is extends System.Windows.Controls.ItemsControl and therefore requires a HierarchicalDataTemplate. Your second mistake was declaring the RibbonTab inside the template, as #devhedgehog mentioned in a comment.
You third mistake was setting the x:Key value for your DataTemplate and applying it to the Ribbon.ItemsTemplate property... I know, I know... a sensible enough thing to do if this wasn't a RibbonControl. You'll have to ask those developers as to why that doesn't work, but you're better off just accepting that it doesn't and adapting your code. You just need to remove the x:Key value and the Ribbon.ItemsTemplate property and let the Framework apply the template implicitly.
Now if you ever want more than one RibbonGroup, then your fourth mistake was defining that in the template for the RibbonTab. If you're going to do this properly, then your data classes will need to match the various levels of UI elements in the Ribbon. By this, I mean that you need to create a RibbonGroupData class too. That class needs a collection of RibbonButtonData objects that supply the data to each RibbonButton in the UI. So you should end up with something like this:
public class RibbonTabData : BaseDataType
{
private string name = string.Empty;
private ObservableCollection<RibbonGroupData> ribbonGroupData = new ObservableCollection<RibbonGroupData>();
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); }
}
public ObservableCollection<RibbonGroupData> RibbonGroupData
{
get { return ribbonGroupData; }
set { ribbonGroupData = value; NotifyPropertyChanged("RibbonGroupData"); }
}
}
public class RibbonGroupData : BaseDataType
{
private string name = string.Empty;
private ObservableCollection<RibbonButtonData> ribbonButtonData = new ObservableCollection<RibbonButtonData>();
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); }
}
public ObservableCollection<RibbonButtonData> RibbonButtonData
{
get { return ribbonButtonData; }
set { ribbonButtonData = value; NotifyPropertyChanged("RibbonButtonData"); }
}
}
public class RibbonButtonData : BaseDataType
{
private string name = string.Empty;
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); }
}
}
The BaseDataType class just implements the INotifyPropertyChanged interface. Of course, you'd need to add extra properties for ICommands and image sources, etc. You might even need different RibbonButtonData classes with different properties for different types of RibbonButtons and then you'd need a common RibbonButtonBaseData class that they all extended, so your collection could contain all the different types together. So there's lots more for you to do, but given this example code, you could display it in the Ribbon like this:
<Ribbon:RibbonWindow.Resources>
<HierarchicalDataTemplate DataType="{x:Type DataTypes:RibbonTabData}"
ItemsSource="{Binding RibbonGroupData}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type DataTypes:RibbonButtonData}">
<Ribbon:RibbonButton Label="{Binding Name}"
LargeImageSource="/WpfRibbonApplication1;component/Images/LargeIcon.png" />
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type DataTypes:RibbonGroupData}"
ItemsSource="{Binding RibbonButtonData}">
<Ribbon:RibbonGroup Header="{Binding Name}" />
</HierarchicalDataTemplate>
</Ribbon:RibbonWindow.Resources>
<Ribbon:Ribbon x:Name="Ribbon" ItemsSource="{Binding RibbonTabData}" />
Now in the view model that is set as the DataContext for the Window, I can add some dummy data to test that it all works:
RibbonTabData.Add(new RibbonTabData() { Name = "Tab 1", RibbonGroupData = new ObservableCollection<RibbonGroupData>() { new RibbonGroupData() { Name = "Group 1", RibbonButtonData = new ObservableCollection<RibbonButtonData>() { new RibbonButtonData() { Name = "Button 1" }, new RibbonButtonData() { Name = "Button 2" }, new RibbonButtonData() { Name = "Button 3" } } }, new RibbonGroupData() { Name = "Group 2", RibbonButtonData = new ObservableCollection<RibbonButtonData>() { new RibbonButtonData() { Name = "Button 1" }, new RibbonButtonData() { Name = "Button 2" } } } } });
RibbonTabData.Add(new RibbonTabData() { Name = "Tab 2" });
RibbonTabData.Add(new RibbonTabData() { Name = "Tab 3" });
And we get this:
However, even with this helpful start, you've still got a lot more work to do.
By reading Sheridans answer I managed to create the following result:
(Different controls with the possibility to attach event handlers to wanted control).
How I did the event handling (example with ribbonbutton)
Attach a tag property to your ribbonbutton template (with databinding of course)
Attach an loaded event into your ribbonbutton template
Create a dictionary: (in your windowname.xaml.cs
public Dictionary<string, List<RoutedEventHandler>> EventLibrary = new Dictionary<string, List<RoutedEventHandler>>();
Add an event to dictionary and extend the string with type of event
EventLibrary.Add("NAME_RIBBONBUTTON_CLICKEVENT", new List<RoutedEventHandler> { new RoutedEventHandler(RibbonButton_Test)});
This is the event loaded code:
private void RibbonButton_Loaded(object sender, EventArgs e)
{
System.Windows.Controls.Ribbon.RibbonButton cmd = (System.Windows.Controls.Ribbon.RibbonButton)sender;
if (EventLibrary.ContainsKey(cmd.Tag.ToString() + "_CLICKEVENT"))
{
List<RoutedEventHandler> value = EventLibrary[cmd.Tag.ToString() + "_CLICKEVENT"];
for (int i = 0; i < value.Count; i++)
{
cmd.AddHandler(RibbonButton.ClickEvent, value[i]);
}
}
}
Here is a link to old post in WPF blog, there you can download archive with solution, where you can find couple of useful things:
ViewModels for all Ribbon controls
Styles with all appropriate bindings
So at the end using above things I receive more simple solution:
<HierarchicalDataTemplate DataType="{x:Type ribbonVM:RibbonTabVM}" ItemsSource="{Binding Groups}">
<RibbonTab DataContext="{Binding}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ribbonVM:RibbonGroupVM}" ItemsSource="{Binding Controls}">
<RibbonGroup DataContext="{Binding}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type ribbonVM:RibbonButtonVM}">
<RibbonButton DataContext="{Binding}" />
</DataTemplate>
The only thing I added to VMs were collections of child elements.
Is that even possible? I have two ObservableCollections. I want to bind and populate a listbox with one of them. For example let's say that we have 2 buttons - one for Twitter and one for Facebook. Clicking on a Facebook button it will populate listbox with friend's names from facebook observable collection and it will bind it. Clicking on Twitter it will populate listbox with Twitter followers and populate listbox and bind it.
How to choose which collection will be populated in listbox?
I would just use one observable collection and fill based on the users choice. You could also fill it with the names from both sources and have a filter to filter out one or the other (apparently you need a wrapper object where you can indicate whether the name is a facebook friend or twitter follower).
Edit: Here is some quick code example of how you can do it:
public interface ISocialContact
{
string Name { get; }
}
public class FacebookContact : ISocialContact
{
public string Name { get; set; }
public string FacebookPage { get; set; }
}
public class TwitterContact : ISocialContact
{
public string Name { get; set; }
public string TwitterAccount { get; set; }
}
Then in your data context:
public ObservableCollection<ISocialContact> Contacts { get; set; }
...
Contacts = new ObservableCollection<ISocialContact> {
new FacebookContact { Name = "Face", FacebookPage = "book" },
new TwitterContact { Name = "Twit", TwitterAccount = "ter" }
};
And in your xaml:
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:FacebookContact}">
<TextBlock Text="{Binding FacebookPage}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TwitterContact}">
<TextBlock Text="{Binding TwitterAccount}"/>
</DataTemplate>
</Grid.Resources>
<ListBox ItemsSource="{Binding Contacts}" Width="100" Height="100"/>
</Grid>
This will apply the appropriate template to each object in your collection. So you can have collection with just facebook contacts or just twitter contacts or mixed.
Also note: You do not need the common interface. It will also work if you just make your ObservableCollection of type object. But given that they are being displayed by the same app in the same list box indicates that you can find some kind of common base and either can create a comon interface or base class.
In your ViewModel, create a property that exposes one or the other ObservableCollection, and swap it out when the button is clicked:
private ObservableCollection<string> _twitterFriendList;
private ObservableCollection<string> _facebookFriendList;
private ObservableCollection<string> _selectedFriendList;
public ObservableCollection<string> SelectedFriendList
{
get { return _selectedFriendList; }
set
{
if (value != _selectedFriendList)
{
_selectedFriendList = value;
RaisePropertyChanged("SelectedFriendList");
}
}
}
void TwitterButton_Click(object sender, RoutedEventArgs e)
{
SelectedFriendList = _twitterFriendList;
}
void FacebookButton_Click(object sender, RoutedEventArgs e)
{
SelectedFriendList = _facebookFriendList;
}
Then in your XAML you can just bind to the property:
<ListBox ItemsSource="{Binding SelectedFriendList}"/>
A non-elegant way of accomplishing this is to put 2 listboxes in the same location and bind 1 to the twitter collection and the other to the facebook collection. Bind their visibility to a property that changes based upon the button clicks. Personally, I'd have 2 radio buttons and display the listbox based upon which one is selected.
<ListBox Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Path=TwitterCollection}" SelectedItem="{Binding Path=SelectedTwitterItem}" Visibility="{Binding Path=IsTwitterSelected, Converter={StaticResource visibilityConverter}}" />
<ListBox Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Path=FacebookCollection}" SelectedItem="{Binding Path=SelectedFacebookItem}" Visibility="{Binding Path=IsFacebookSelected, Converter={StaticResource visibilityConverter}}" />
<RadioButton Grid.Row="1" Grid.Column="0" GroupName="rdoOptions" Content="{Binding Path=TwitterLabel}" IsChecked="{Binding Path=IsTwitterSelected}" />
<RadioButton Grid.Row="1" Grid.Column="1" GroupName="rdoOptions" Content="{Binding Path=FacebookLabel}" IsChecked="{Binding Path=IsFacebookSelected}" />