Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Databinding Examples in WPF for VB.NET

0.00/5 (No votes)
9 Sep 2013 1  
Databinding examples in WPF for VB.NET.

Introduction

This article goes through the different ways to bind an element in WPF for VB.NET.

Background

Being new to WPF, I’ve googled and read a few different books on how to bind controls to data but none of them seemed to be able to put together the full picture for me:

  • Some had too complex of an example or only snippets of code out of context
  • Every article was binding a different way
  • Almost everything was in C# and written several years ago

This is my attempt to cover all the different ways of data binding with simple examples and walk-through some of the differences in WPF vs. Windows Forms. 

Using the code 

Hard-coding the data in XAML

First let’s start off with an example of no binding:

  • Create a new VB.Net WPF project and call it “bindtolist”
  • This will give you the usual MainWindow.xaml

In MainWindow.xaml, we’ll drag a button and a listbox in the designer to the WPF window and given the listbox a name of listbox1. We’ll add a few items in XAML directly or using the items Collection in the properties window.:

MainWindow.xaml 

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="314" Width="289.8">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1">
            <ListBoxItem>One</ListBoxItem>
            <ListBoxItem>Two</ListBoxItem>
            <ListBoxItem>Three</ListBoxItem>
        </ListBox>
    </Grid>
</Window>

If you double click the button, the designer will create a click event for you. We can then reference the listbox in the code-behind and add a new item. If you’re familiar with windows forms, you should feel right at home. The designer

MainWindow.xaml.vb

Class MainWindow
    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        listbox1.Items.Add("New item")
    End Sub
End Class

You can see the application will run as expected.

No Binding – with codebehind (Items.Add)

Since we want to tie the listbox to some data. Let’s remove the Listbox items and put it in the codebehind.

MainWindow.xaml

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="314" Width="289.8">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1"/>
    </Grid>
</Window>

MainWindow.xaml.vb

Class MainWindow
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()  
        ' Add any initialization after the InitializeComponent() call.
        listbox1.Items.Add("One")
        listbox1.Items.Add("Two")
        listbox1.Items.Add("Three")
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        listbox1.Items.Add("New item")
    End Sub
End Class

Now everything still looks the same but we’ve moved the XAML code to the code behind. Now let’s move it to a list. This is still pretty much like Windows Forms.

Binding – with codebehind (ItemsSource)

Here is where things start to get a little different. Listbox now has a ItemsSource property, so we can add a list all at once to a listbox.

Class MainWindow
    Public lst1 As New ArrayList 
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()  
        ' Add any initialization after the InitializeComponent() call.
        lst1.Add("one")
        lst1.Add("two")
        lst1.Add("three")
        listbox1.ItemsSource = lst1
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        lst1.Add("New Item")
        listbox1.ItemsSource = Nothing
        listbox1.ItemsSource = lst1
    End Sub
End Class

Now that we’ve changed it to a list and set it, we can no longer add items. If we try we’ll get the “operation is not valid while itemssource is in use” error. What we’d need to do is to clear out the list and re-add it. Clearly this is a terrible way to update a list, but I find it interesting how many different ways there are to update a list.

Binding – with code-behind (ObservableCollection)

By changing the arraylist to an observableCollection, we can now update just the list and the listbox will follow! This is called a two-way binding.

Class MainWindow
    Public lst1 As New ObservableCollection(Of String)
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()  
        ' Add any initialization after the InitializeComponent() call.
        lst1.Add("one")
        lst1.Add("two")
        lst1.Add("three")
        listbox1.ItemsSource = lst1
    End Sub  
    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        lst1.Add("New Item")
    End Sub
End Class

XAML target binding with codebehind (ObservableCollection) source

OK, now it becomes tricky. When we have the XAML reference something in the code-behind, it needs to talk to a public property and not a public variable. What’s annoying is that the application won’t error, your listbox just won’t show anything. Also, your constructor (the New() function), needs to be parameter-less. You can’t even have Optional parameters. This will become more of an issue later when we start binding to other classes. When you starting adding bindings to the XAML code, remember the designer is pretty buggy. Always build your code or restart the VS application if the errors start to sound strange. When you have parameters, you should get a “not a valid constructor” error.

Imports System.Collections.ObjectModel
Class MainWindow
    Public Property lst1 As New ObservableCollection(Of String)
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()  
        ' Add any initialization after the InitializeComponent() call.
        lst1.Add("one")
        lst1.Add("two")
        lst1.Add("three")
        listbox1.ItemsSource = lst1
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        lst1.Add("New Item")
    End Sub
End Class

When binding, we need to tell XAML where to bind to. Since all our code is in the MainWindow.vb class, we can just reference that class by referencing the window itself if we give it a name. The path is the property we want to bind to.

<Window x:Class="MainWindow"
    Name="w1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="314" Width="289.8">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1" ItemsSource="{Binding ElementName=w1, Path=lst1}"/>
    </Grid>
</Window>

XAML target binding with code-behind (ObservableCollection) source

If we set the datacontext in the window to itself, we don’t need to keep specifying the ElementName for each property we want to use in the MainWindow class.

<Window x:Class="MainWindow"
    Name="w1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="MainWindow" Height="314" Width="289.8">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1"  ItemsSource="{Binding Path=lst1}"/>
    </Grid>
</Window>

We could also could have set the datacontext in the code-behind using Me.DataContext instead of in XAML.

Imports System.Collections.ObjectModel
Class MainWindow
    Public Property lst1 As New ObservableCollection(Of String) 
    Public Sub New()  
        ' This call is required by the designer.
        InitializeComponent()  
        ' Add any initialization after the InitializeComponent() call.
        lst1.Add("one")
        lst1.Add("two")
        lst1.Add("three")
        Me.DataContext = Me
    End Sub
  
    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        lst1.Add("New Item")
    End Sub
End Class

Binding with Namespaces

Now, by default, VB.NET doesn’t use namespaces. However, if you’ve seen any C# code, you’ve probably noticed a lot of local namespace references. The same is possible in VB.NET and is a good intro into more complex setups.

Let’s wrap our class in a namespace. We already have an instance of MainWindow in our XAML, so it wouldn’t make too much sense to try to create another window instance in XAML. Instead, we should break out the list data into its own class. We can still keep everything in the same namespace. Here we use a couple of things we mentioned before:

  • We need to bind to a property – we’ve kept the lst1 property we had before
  • Our New constructor still has no parameters
  • A new rule: we can’t bind to subclasses

In order to add items to the lst1, we now need to reference the class instantiated in the XAML.

Imports System.Collections.ObjectModel
Namespace MW
    Public Class MainWindow  
        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
        End Sub  
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
            Dim ld As list_data = Me.Resources("ld")
            ld.lst1.Add("New Item")
        End Sub
    End Class
  
    Public Class list_data
        Public Property lst1 As New ObservableCollection(Of String)
        Public Sub New()
            lst1.Add("one")
            lst1.Add("two")
            lst1.Add("three")
        End Sub
    End Class
End Namespace

You’ll notice a few things here:

  • Since MainWindow is now in a namespace, we need to reference its class differently
  • In order to instantiate a new class, we need to reference its namespace using xmlns. We’ve given a nickname to the namespace called local. Local is the usual convention when referring to your current assembly namespace
  • We’ve now added a resource. This is the equivalent of creating a new list_data class
  • Once we have our class, we can reference it in our binding as a source and use its lst1 property
<Window x:Class="MW.MainWindow"
    Name="w1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:bindtolist.MW"
    Title="MainWindow" Height="314" Width="289.8">
    <Window.Resources>
        <local:list_data x:Key="ld"/> 
    </Window.Resources>    
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1" 
          ItemsSource="{Binding Source={StaticResource ld}, Path=lst1}"/>
    </Grid>
</Window>

Wow, that’s a lot of stuff. Clearly we must almost be done? Truly there is a dizzying mix of bindings. Wait till I get going! Now, where was I?

Now that we have a context that isn’t our MainWindow class, we can embed context in other things like the grid.

<Window x:Class="MW.MainWindow"
    Name="w1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:bindtolist.MW"
    Title="MainWindow" Height="314" Width="289.8">
    <Window.Resources>
        <local:list_data x:Key="ld"/> 
    </Window.Resources>
    <Grid DataContext="{StaticResource ld}">
        <Button Content="Button" HorizontalAlignment="Center" 
           Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1"  ItemsSource="{Binding Path=lst1}"/>
    </Grid>
</Window>

But what if we want to instantiate and set the datacontext at the same time?

<Window x:Class="MW.MainWindow"
    Name="w1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:bindtolist.MW"
    Title="MainWindow" Height="314" Width="289.8">
    <Window.DataContext>
        <local:list_data />
    </Window.DataContext>
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
                 Width="75" Click="Button_Click" Margin="104,10,104.2,251"/>
        <ListBox Margin="50" Name="listbox1"  ItemsSource="{Binding Path=lst1}"/>
    </Grid>
</Window>

We now reference the data_list like this.

Imports System.Collections.ObjectModel
Namespace MW
    Public Class MainWindow
        Public Sub New()
            ' This call is required by the designer.
            InitializeComponent()
        End Sub  
        Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
            Dim ld As list_data = Me.DataContext 
            ld.lst1.Add("New Item")
        End Sub
    End Class

    Public Class list_data
        Public Property lst1 As New ObservableCollection(Of String)
        Public Sub New()
            lst1.Add("one")
            lst1.Add("two")
            lst1.Add("three")
        End Sub
    End Class
End Namespace

This hopefully covers most of the different binding scenarios that you’ll see in WPF code mixing code-behinds and XAML instances without being too complicated.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here