Yes, you have to set a binding context in your Window in order for binding to work. "Do I do it in the form or do I do it in XAML?" is a sometimes stylistic choice in the WPF community, but for many reasons you usually end up doing it in code-behind.
"So why bother with XAML at all?" is a very good question almost everyone tends to ask after seeing that. Let's talk in metaphor.
Think about a car stereo with just a radio. You can tune the station, and you can change the volume. That implies some things about UI, but not a specific UI. Here's some different ways car stereo radios are implemented:
- Digital displays may show the current station.
- A needle might show the current station.
- A knob may be used to change the current station.
- A set of buttons may be used to change the current station.
- A knob may be used to change the volume.
- A set of buttons may be used to change the volume.
If we design our stereo for it, we might opt to make several different faceplates with different combinations of those choices. Then, someone can buy exactly the faceplate they want, plug that in, and use the stereo. It's the same stereo and works the same way, but we've changed the UI.
That's how WPF is supposed to work. XAML is the faceplate. ViewModels are the stereo. We have to do a tiny bit of work in the code-behind to connect the two, that's the "plugging in a faceplate" step.
That makes it a little tough to talk about WPF on forums sometimes, because it takes more than one file to pull together an example. This is a quick example of getting a ListView working. Especially when I was just starting out in WPF, I found it was always easier to start with something quick and dirty then refine it to something more advanced:
MainViewModel.vb:
Code:
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Public Class MainViewModel
Implements INotifyPropertyChanged
Private _items As ObservableCollection(Of String)
Public Property Items As ObservableCollection(Of String)
Get
Return _items
End Get
Private Set(value As ObservableCollection(Of String))
_items = value
OnPropertyChanged(New PropertyChangedEventArgs("Items"))
End Set
End Property
Public Sub New()
_items = New ObservableCollection(Of String)()
_items.Add("One")
_items.Add("Two")
_items.Add("Several")
End Sub
Protected Sub OnPropertyChanged(ByVal e As PropertyChangedEventArgs)
RaiseEvent PropertyChanged(Me, e)
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
End Class
MainWindow.xaml
Code:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp7"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView ItemsSource="{Binding Items}"/>
</Grid>
</Window>
(You'll have to edit the xmlns:local namespace.)
MainWindow.xaml.vb
Code:
Class MainWindow
Public Sub New()
InitializeComponent()
DataContext = New MainViewModel()
End Sub
End Class
All bindings are relative to the DataContext, so we need to make sure SOMETHING sets the DataContext to an instance of MainViewModel. If we really, REALLY wanted to adhere to "do nothing in code-behind", we could use this XAML:
Code:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp7"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<ListView ItemsSource="{Binding Items}"/>
</Grid>
</Window>
I think this is needlessly dogmatic. It only works if your ViewModel can be created via a parameterless constructor, and in most modern projects that's impractical. I used to stress about this, but here's a better way to look at it:
"With no code behind" is a thing people write in MSDN magazine for the same reason they write, "With zero lines of code". It's there to sell copies of software.
If you learn how to use MVVM, you will write very little code behind, and most of your files will only have the bit of code to set the DataContext in them. However, many MVVM frameworks have infrastructure to do that for you. In those, you tend to never actually use code-behind.
But as you're learning WPF, if the only way you can get something done is with code-behind, I say do it. Then, when it works, post on the forums and ask how to do it without code-behind. It's easier to explain how to transform working code than it is to explain the example without context.