views:

61

answers:

3

I'm new to WPF and trying to figure out all this databinding stuff. When I do the following in my code, my ComboBox is populated when I run my application:

public NewForm()
{
    InitializeComponent();
    Product.ItemsSource = Products;
}

public List<string> Products
{
    get { return _productsComponents.Keys.ToList(); }
}

However, in my XAML when I have the following, the ComboBox has no content in it when I run my application:

<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0"
          Name="Product" VerticalAlignment="Top" Width="120"
          ItemsSource="{Binding Path=Products}"/>

Am I referencing something incorrectly? This tutorial was helpful but he never set ItemsSource in XAML, always in C#.

A: 

Try Binding Source=Products

Path is generally an addenda on Source from how I've used it, it's for when you need to access a subproperty of the elements available in the source.

Here's an example of a ListBox I have filled with elements from an XDocument stored in the static resources. This might hopefully explain the relationship between Binding Source and Path. Root.Elements is the member path to a collection supine to the XDocument referenced in the Source. Don't use the {StaticResource Product} mechanism in yours as you don't have your collection in the app xaml, but rather the current class.

<ListBox Height="660" Name="ResponsesListBox" Width="240"
                      MouseDoubleClick="ResponsesListBox_MouseDoubleClick"
                      MouseLeftButtonDown="WindowMoveHandler"
                      ItemsSource="{Binding Source={StaticResource ResponsesXDocument}, Path=Root.Elements}"
                      ItemTemplate="{StaticResource ListBoxDataTemplate}" />

Also handy is this WPF Data Binding Cheat Sheet, I have found it quite helpful: http://www.nbdtech.com/Blog/archive/2009/02/02/wpf-xaml-data-binding-cheat-sheet.aspx

Jimmy Hoffa
Er, that causes my ComboBox in the application to contain list items 'p', 'r', 'o', 'd', 'u', 'c', 't', 's'. :(
Sarah Vessels
+2  A: 

By default, you're actually binding not to the form itself, but to the object assigned to the DataContext property. This facilitates using a view model to manage all the data outside the codebehind files.

You can probably assign the form itself to the DataContext property in the constructor

DataContext = this;

You can also bind to the form in any of several ways. Here is one:

<Window x:Name="thisWindow" …
    <ComboBox ItemsSource="{Binding Path=Products, ElementName=thisWindow}"…

I don't think that Products needs to be a DependencyProperty here, but don't quote me on that, and as long as the collection is not subject to change, you don't need to worry about update notifications.

Jay
Having `<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0" Name="Product" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Path=Products, ElementName=thisWindow}"/>` still gives me an empty ComboBox when I run the app. :(
Sarah Vessels
Ooh, setting `DataContext = this;` in my constructor worked when I just have `<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0" Name="Product" VerticalAlignment="Top" Width="120" ItemsSource="{Binding Path=Products}"/>` in the XAML. Thanks!
Sarah Vessels
@Sarah In the first case, did you assign the name "thisWindow" in the Window element? `x:Name="thisWindow"`
Jay
Excellent! No, I hadn't. Set the `x:name` attribute and then the `ElementName=thisWindow` worked. No need for C# stuff, yay!
Sarah Vessels
@Jay Products does not _need_ to be a DepependencyProperty. In fact, it'd probably make more sense that it isn't.
myermian
@myermian You're right. I'm not sure it makes sense for the window to implement `INotifyPropertyChanged` and subscribe to its own event, either. Moot if the collection is static.
Jay
A: 

I'd suggest trying to limit myself to either keeping the binding setup in code or in XAML, not mixing them. In you're situation, you're setting the ItemsSource upon form creation AND in XAML. I'm not sure why?

Anyways, it seems that you're '_productsComponents' is a Dictionary by your code. So I'm going to use that to my advantage in a better code version:

CODE-BEHIND:

public partial class NewForm : Window
{
    private Dictionary<String, String> _productsComponents;
    public Products
    {
        get { return _productsComponents; }
        set { _productsComponents= value; }
    }

    public NewForm()
    {
        Products = new Dictionary<String, String>();
        //Do you're dictionary loading...

        InitializeComponent();

        DataContext = this;

        ProductCmbBox.ItemsSource = Products;
        ProductCmbBox.SelectedValuePath = "Key";
        ProductCmbBox.DisplayMemberPath = "Value"; //or "Key" if you want...
    }
}

<ComboBox x:Name="ProductCmbBox" ... />

I'd also look into: Dr. WPF's ObservableDictionary. It allows you to make sure that if the Dictionary items change that you're combobox (UI) will be able to observe that change accordingly (that is, if you remove/add a keyvaluepair from you're dictionary that you're combobox will show the correct list always).

myermian
Oh, and if you're new to WPF I'd look at picking up a book if you're coming from another language... adjusting to how WPF does things is a bit of a learning curve. I picked up Pro WPF in C# 2010. It says Pro, but it isn't too complex. Book + StackOverflow + Dr. WPFs website = great way to pickup WPF.
myermian