Bind Combobox Itemsource to Static Dictionary (Silverlight) - silverlight

I am trying to bind the ItemsSource of my ComboBox to a static dictionary I have on a static class.
In WPF I would use the following which would work fine:
ItemSource="{x:Static objectModel:LocaleHelper.FriendlyNames}"
Where LocaleHelper is the class name and FriendlyNames is the dictionary property of which I wish to bind to.
However in Silverlight I get an error to do with the type x:Static not being found.
Could anyone explain to me what the issue is and the workaround?
I have looked around but couldn't find any detailed explanations.
Sorry if this is a simple issue - I'm new to Silverlight and also WPF in general.
EDIT:
After having done some more reading it looks like silverlight does not support static resources. Furthermore Dictionaries do not seem to update property changed / support DisplayMemberPath & SelectedValue so having the dictionary as a field in my viewmodel doesn't seem to be an option either.

You can only bind to non-static public properties (not fields). But you can use any "carrier" for those properties (so you are not forced to have those properties in the ViewModel). Let's see...
<Resources>
<LocaleHelperWrapper x:Key="Wrapper"/>
</Resources>
<ComboBox ItemsSource="{Binding Path=FriendlyNames,
Source={StaticResource Wrapper}}"/>
And the wrapper code:
public class LocaleHelperWrapper
{
public Dictionary<string, string> FriendlyNames
{
get { return LocaleHelper.FriendlyNames; }
}
}
[Edit] The ComboBox supports DisplayMemberPath and SelectedValue. Assuming you want to use the ComboBox to select the Key and display the Value of you Dictionary's KeyValuePairs:
<ComboBox
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=MySelectionViewModel.SelectedKey, Mode=TwoWay}"
ItemsSource="..."/>

If it's merely an issue of binding to a collection, you might as well do it in the constructor of the ViewModel. Further consider using an ObservableCollection in case your static collection changes over time.

Related

How do I bind a "list" of strings to a ComboBox in WPF?

I basically want to take a bunch of names in a collection and bind them to a combobox. For example:
Bill
Jack
Bob
Kevin
and have those items in a collection and have it bound to the ComboBox. I'm not sure if the list will be updated dynamically or not, but I prefer to plan for it to be. Any help would be appreciated. I've been trying for a few hours now and can't figure it out. I want to do it in XAML and not the code-behind. In the code-behind,
MyComboBox.ItemsSource = MyObservableCollection;
works fine. I don't know how to do that in XAML though with the collection declared in the code-behind.
Thanks in advance (again), community.
*EDIT:
This is how I have the collection declared and accessible.
public ObservableCollection<string> propertynames
{
get {return _propertynames;}
}
private ObservableCollection<string> _propertynames;
The last thing I tried was this:
<Window.Resources>
<CollectionViewSource Source="{Binding propertynames}" x:Key="srcSort"/>
</Window.Resources>
....
<ComboBox x:Name="cboSort" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="256" Background="WhiteSmoke" Margin="12,50,0,0" FontSize="12pt"
Height="27.28"
SelectedIndex="0"
SelectionChanged="cboWorkCenters_SelectionChanged"
ItemsSource="{Binding Path = {StaticResource srcSort}}">
</ComboBox>
....
I'm a total n00b to this stuff. Been in it about a week now, so I may have done something really obvious to a seasoned user.
*EDIT #2
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:WpfApplication1"
Title="Window1" Height="226" Width="242"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ComboBox Margin="43,71,40,77"
Name="comboBox1"
ItemsSource="{Binding ob}" />
</Grid>
</Window>
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public ObservableCollection<string> ob
{
get
{
return _ob;
}
}
private ObservableCollection<string> _ob = new ObservableCollection<string>();
public Window1()
{
InitializeComponent();
FillObj();
//comboBox1.ItemsSource = ob;
}
private void FillObj()
{
for (int i = 1; i < 6; i++)
{
_ob.Add(i.ToString());
}
}
}
}
Made above real simple project just to see if I was doing it all wrong. This worked fine so something else must be causing it to fail.
*EDIT #3
*PROBLEM FIXED
For God's sake, I figured it out. I've been on this for HOURS and it's just silly what's caused it to fail.
The solution is this: I wasn't instantiating _propertynames when I declared it. I was querying the class properties with Linq to get the list of properties and then created _propertynames by passing ...GetProperties.ToList<...>() to the constructor. Apparently, you have to instantiate the variable so it hits during InitializeComponent. Unreal.
Once I did that and then added the items to it after the fact, it worked fine.
I wish WPF had a face so I could punch it. I know it's my ignorance of how it works, but I really could have used some kind of message.
Thanks guys for the help. Both of your suggestions were useful once I took care of the root issue.
private ObservableCollection<string> _propertynames
needs to be
private ObservableCollection<string> _propertynames = new ObservableCollection<string>()
There are countless ways of doing this. Once you've created the collection in code-behind, you can:
Call Resources.Add to add it to the window's resource dictionary, and then bind to the resource, e.g. ItemsSource="{Binding {DynamicResource MyList}}".
Give the ComboBox a name (using the x:Name attribute) and set its ItemsSource explicitly in code, e.g. MyComboBox.ItemsSource = myCollection;.
Create a class, make the collection a property of the class, and set the window's DataContext to an instance of that class and bind to it directly, e.g. ItemsSource = "{Binding MyCollectionProperty}".
Make the collection a property of the window, set the window's DataContext to this, and bind to the property (this is essentially the same technique as #3, only you're not creating a new class).
Without setting the window's DataContext, you can still reference a property on it using binding as long as you've given it a name, e.g. {Binding ElementName=MyWindow, Path=MyCollection}. (This is the same as Ross's suggestion.)
Or, without giving the window a name, you can use RelativeSource binding to find the ancestor Window and bind to a property on it. I don't have any confidence in my ability to write a working binding expression that uses RelativeSource off the top of my head, so I'll leave that as an exercise for the reader.
You can set the DataContext of the ComboBox to the instance of your collection, and then set itsItemsSource to {Binding}. You probably wouldn't do this in practice; I mention it just because it seems to be a common mistake for people to set the DataContext of a control without also setting a binding, and then wonder why content from the bound object isn't showing up.
(While I've said "window" in the above, everything I've said is also true for user controls.)
I'm sure there are at least five other ways to do this that I'm not thinking of. Binding is really, really flexible.
What have you tried so far?
I would approach it as follows, assuming the combo box is within a UserControl with a code-behind class containing the public property MyObservableCollection:
<UserControl x:Name="MyCollectionOwnerControl">
<ComboBox ItemsSource="{Binding ElementName=MyCollectionOwnerControl, Path=MyObservableCollection, Mode=OneWay}" />
</UserControl>

WPF - how to update textbox with currently selecteditem in listview? Using MVVM!

I'd be grateful if someone could give me some pointers on a very annoying problem I'm having - I'm going crazy trying to make this work as I'm sure there must be a simple solution but I can't see it!
As a result of the very helpful answers to my previous question posted on here, I'm attempting to use the MVVM approach in WPF.
I've got a listview in one page that binds to an ObservableCollection in the viewmodel & the listview's selected item is bound to a property called SelectedEntity in the viewmodel:
<Listview Name="listview" ItemsSource="{Binding Entities}" SelectedItem="{Binding SelectedEntity, Mode=TwoWay}">
In a different page I have a textbox bound to the Name property of SelectedEntity in the viewmodel:
<TextBlock Text="{Binding Path=SelectedEntity.Name}" />
The code in the viewmodel is:
Private Entity selectedEntity;
Public Entity SelectedEntity
{
get
{
return selectedEntity;
}
set
{
if (selectedEntity != value)
{
selectedEntity = value;
RaisePropertyChanged("SelectedEntity");
}
}
RaisePropertyChanged is a method that implements INotifyPropertyChanged.
What I want to do is have the textblock update when the currently selected item in the listview changes but it just won't? Am I missing something really obvious?
Thanks very much for any guidance you can give me!
I got this working using the MVVM Light Toolkit and have uploaded it here
It works because the ViewModelLocator holds a static reference to the ViewModel

how to build dynamic grid and binding to xaml using mvvm

I'm planning a WPF application which will build dynamic grid with textblocks in the viewmodel and then refresh interface (xaml) with the new grid.
I've done the firts step, but i have problems to refresh the view with the new grid.
Is there any example code of how to bind the grid to the xaml that I can have a look at?? I really can't figure this out!
Thanks
You may be approaching this slightly wrongly, hard to say from the question-
Generally to show a dynamic set of UI elements in MVVM you bind the ItemsSource property of an ItemsControl to an ObservableCollection. The ItemsControl ItemsTemplate property converts the YourViewModel object into a UIElement which can be a TextBlock or whatever style you want.
So as an example:
// model
class Person
{
public string Name {get; private set;}
}
// view model
class MainViewModel
{
public ObservableCollection<Person> People {get; private set;}
}
//view
<UserControl DataContext="{Binding MyMainViewModelObject}">
<ItemsControl ItemsSource="{Binding People}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>/
</ItemsControl.ItemsTemplate>
</ItemsControl>
</UserControl>
I havent tested that code, it is just to illustrate. There are other ways of dissecting the problem into MVVM, it all depends on the situation. You would have to give more details for us to help you out with that. Rarely in WPF is there a need to use code to create or add UI elements to other UIElements etc.
A point to note more along the exact lines of the question however is that an ItemsControl can either bind to a bunch of regular objects and use it's template to create UIElements from them, OR it can bind to a list of UIElements, in which case the template is not applied (sounds like this is the situation you have).

WPF Combobox databinding to a L2S table

Here is what i have:
a SQL CE database, that holds this Category table, with id and name columns only.
dbml generated with sqlmetal
singleton (static class) that exposes the linq DataContext.
in the code-behind file, i have a property like follows:
private System.Data.Linq.Table<Categories> Categories
{
get
{
return LibraryDataStore.Instance.Categories;
}
}
I want to simply bind the categories to a ComboBox. Can't believe i've been at it for hours now, with no result :(
I don't want to set ItemsSource in the code behind, I want to do this XAML-only, but how?
Most examples i found were defining the data right there in XAML, or setting ItemsSource programatically, but that is not what i want.
Why isn't this, for example, working?
<ComboBox Name="cmbCategory"
Margin="3"
MinWidth="200"
ItemsSource="{Binding Path=Categories}"
DisplayMemberPath="Name"/>
As a side note, i want to say that I find the databinding model of wpf extremely difficult to learn, as it is so thick and there are just SO MANY WAYS to do things.
Later edit:
I found that it works if i set the ItemsSource like this:
var cats = from c in LibraryDataStore.Instance.Categories
select c;
cmbCategory.ItemsSource = cats;
Still, I can't figure it out why it doesn't work in XAML.
You must set the datacontext of the UserControl to LibraryDataStore.Instance. This datacontext will then filter down the visual tree to your combobox (so there is no need to set the datacontext of the combobox itself). Your xaml will then be able to bind to the public property of this object "Categories".
Bea Stollnitz gives a good overview of how to detect problems with databinding (i.e. it failing silently) on her blog -> http://bea.stollnitz.com/blog/?p=52
you need to set the DataContext of your UserControl (or Page) to the current instance :
this.DataContext = this;

WPF Databinding

Can anyone point me to a good resource (or throw me a clue) to show me how to do DataBinding to controls (ComboBox, ListBox, etc.) in WPF? I'm at a bit of a loss when all my WinForms niceities are taken away from me, and I'm not all that bright to start with...
The best resource I've found for WPF data binding is Bea Costa's blog. Start from the first post and read forward. It's awesome.
I find the tutorial videos at Windows Client .Net equally awesome. Dot Net Rocks TV has also covered it some time ago.
in code behind -- set the DataContext of your list box equal to the collection you're binding to.
private void OnInit(object sender, EventArgs e)
{
//myDataSet is some IEnumerable
// myListBox is a ListBox control.
// Set the DataContext of the ListBox to myDataSet
myListBox.DataContext = myDataSet;
}
In XAML, Listbox can declare which properties it binds to using the "Binding" syntax.
<ListBox Name="myListBox" Height="200"
ItemsSource="{Binding Path=BookTable}"
ItemTemplate ="{StaticResource BookItemTemplate}"/>
And some more links, just in case the above didn't suffice:
Windows Presentation Foundation - Data Binding How-to Topics
- Approx 30 'How To' articles from MSDN.
"The topics in this section describe how to use data binding to bind elements to data from a variety of data sources in the form of common language runtime (CLR) objects and XML. "
Moving Toward WPF Data Binding One Step at a Time
- By WPF guru Josh Smith
"This article explains the absolute basics of WPF data binding. It shows four different ways how to perform the same simple task. Each iteration moves closer to the most compact, XAML-only implementation possible. This article is for people with no experience in WPF data binding."
Here's another good resource from MSDN: Data Binding Overview.
There are three things you need to do:
Bind the ItemsSource of the ComboBox to the list of options.
Bind the SelectedItem to the property that holds the selection.
Set the ComboBox.ItemTemplate to a DataTemplate for a ComboBoxItem.
So, for example, if your data context object is a person having email addresses, and you want to choose their primary, you might have classes with these signatures:
public class EmailAddress
{
public string AddressAsString { get; set; }
}
public class Person
{
public IEnumerable<EmailAddress> EmailAddresses { get; }
public EmailAddress MainEmailAddress { get; set; }
}
Then you could create the combo box like this:
<ComboBox ItemsSource="{Binding EmailAddresses}" SelectedItem="{Binding MainEmailAddress}">
<ComboBox.ItemTemplate>
<DataTemplate>
<ComboBoxItem Content="{Binding AddressAsString}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Now you need to implement INotifyPropertyChanged in both Person and EmailAddress. For the EmailAddresses collection, you could back it with an ObjservableCollection.
Or as an alternative you can use Update Controls .NET. This is an open source project that replaces data binding and does not require INotifyPropertyChanged. You can use whatever collection makes sense to back the EmailAddresses property. The XAML works the same as above, except that you import the UpdateControls.XAML namespace and replace {Binding ...} with {u:Update ...}.

Resources