1 2 Previous Next 

WPF: Bind to a ListView


There is not a DataGrid or DataGridView in Windows Presentation Foundation.  Use the ListView to display data in a table.  In the window's Xaml define the listview and the fields you want displayed.  The code behind file is where you get the data from the Northwind database and bind the listview.

The Windows Xaml

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF1" Height="300" Width="300"
    >
  <Grid>
    <ListView Margin="25,22,30,48" Name="ListView1" >
      <ListView.View>
        <GridView >
          <GridViewColumn Header ="Last Name" DisplayMemberBinding="{Binding LastName}" Width="100"></GridViewColumn>
          <GridViewColumn Header ="First Name" DisplayMemberBinding="{Binding FirstName}" Width="100"></GridViewColumn>
        </GridView>
      </ListView.View>
    </ListView>
  </Grid>
</Window>


The Code Behind

Imports System.Data

' Interaction logic for Window1.xaml
Partial Public Class Window1
    Inherits System.Windows.Window

    Public Sub New()
        InitializeComponent()
        Dim dt As New DataTable

        Dim strConn As String = _
           "Server = .\sqlexpress;Database = NorthWind; Integrated Security = SSPI;"
        Dim conn As New SqlConnection(strConn)
        Dim da As New SqlDataAdapter("Select LastName, FirstName from Employees", conn)
        da.Fill(dt)
        ListView1.DataContext = dt
        Dim bind As New Binding
        ListView1.SetBinding(ListView.ItemsSourceProperty, bind)
    End Sub

End Class




WPF OneWay Binding Part 1


Windows Presentation Foundation (WPF) foundation is for building applications and experiences in Windows Vista that blend the application UI, documents, and media content. In this series of blog entries we willl start to explore some of the improvements to data binding in WPF. You will need to have the .Net Framework 3.0, Windows Vista SDK, and Visual Studio 2005 extensions for WPF and WCF installed for this sample.


For this example we will start off with a Windows Application (WPF). In the forms XMAL we will add a stack panel to hold a label and scrollbar. The label's content will be bound to the scrollbar's value so as we move the scrollbar the value will be displayed in the label.


In the Lets set up a DataContext which is bound to the scrollbar .


      <Label   HorizontalAlignment="Center" DataContext="{Binding ElementName=hscroll, Mode=OneWay}"

Now we can bind the label's content to the scrollbars value


      <Label   HorizontalAlignment="Center" DataContext="{Binding ElementName=hscroll, Mode=OneWay}"
               Content="{Binding Path=Value}"  />


The complete XMAL for the Window


<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPFOneWayBind" Height="300" Width="300"
    >
    <Grid>
      <StackPanel>
      <ScrollBar Name="hscroll" Maximum="100"  Minimum="1" SmallChange="1" LargeChange="10" Orientation="Horizontal"></ScrollBar>
      <Label   HorizontalAlignment="Center" DataContext="{Binding ElementName=hscroll, Mode=OneWay}"
               Content="{Binding Path=Value}"  />
      </StackPanel>
    </Grid>
</Window>



WPF OneWay Binding Part 2


In the last part we bound a label to the value of the scrollbar. In this part we will format the scrollbar's value before we display it.


To be able to format the output of a bound value you need a class which inherits from IValueConverter. For this example I am using the NumbersToWords function found here to convert the number to a word for display.



Public Class NumberToWord
    Implements IValueConverter


    Private Function NumbersToWords(ByVal num As Decimal) As String
        Dim power_value(5) As Decimal
        Dim power_name(5) As String
        Dim digits As Integer
        Dim result As String
        Dim i As Integer

        ' Initialize the power names and values.
        power_name(1) = "trillion" : power_value(1) = 1000000000000.0#
        power_name(2) = "billion" : power_value(2) = 1000000000
        power_name(3) = "million" : power_value(3) = 1000000
        power_name(4) = "thousand" : power_value(4) = 1000
        power_name(5) = "" : power_value(5) = 1
        For i = 1 To 5
            ' See if we have digits in this range.
            If num >= power_value(i) Then
                ' Get the digits.
                digits = Int(num / power_value(i))
                ' Add the digits to the result.
                If Len(result) > 0 Then result = result & ", "
                result = result & Words_1_999(digits) & " " & power_name(i)
                ' Get the number without these digits.
                num = num - digits * power_value(i)
            End If
        Next i
        NumbersToWords = Trim$(result)
    End Function

    ' Return words for this value between 1 and 999.
    Private Function Words_1_999(ByVal num As Integer) As String
        Dim hundreds As Integer
        Dim remainder As Integer
        Dim result As String
        hundreds = num \ 100
        remainder = num - hundreds * 100
        If hundreds > 0 Then
            result = Words_1_19(hundreds) & " hundred "
        End If
        If remainder > 0 Then
            result = result & Words_1_99(remainder)
        End If
        Words_1_999 = Trim$(result)
    End Function

    ' Return a word for this value between 1 and 19.
    Private Function Words_1_19(ByVal num As Integer) As String
        Select Case num
            Case 1
                Words_1_19 = "one"
            Case 2
                Words_1_19 = "two"
            Case 3
                Words_1_19 = "three"
            Case 4
                Words_1_19 = "four"
            Case 5
                Words_1_19 = "five"
            Case 6
                Words_1_19 = "six"
            Case 7
                Words_1_19 = "seven"
            Case 8
                Words_1_19 = "eight"
            Case 9
                Words_1_19 = "nine"
            Case 10
                Words_1_19 = "ten"
            Case 11
                Words_1_19 = "eleven"
            Case 12
                Words_1_19 = "twelve"
            Case 13
                Words_1_19 = "thirteen"
            Case 14
                Words_1_19 = "fourteen"
            Case 15
                Words_1_19 = "fifteen"
            Case 16
                Words_1_19 = "sixteen"
            Case 17
                Words_1_19 = "seventeen"
            Case 18
                Words_1_19 = "eightteen"
            Case 19
                Words_1_19 = "nineteen"
            Case Else
                Words_1_19 = ""
        End Select
    End Function

    ' Return a word for this value between 1 and 99.
    Private Function Words_1_99(ByVal num As Integer) As String
        Dim result As String
        Dim tens As Integer
        tens = num \ 10
        If tens <= 1 Then ' 1 <= num <= 19
            result = result & " " & Words_1_19(num)
        Else
            ' 20 <= num
            ' Get the tens digit word.
            Select Case tens
                Case 2
                    result = "twenty"
                Case 3
                    result = "thirty"
                Case 4
                    result = "forty"
                Case 5
                    result = "fifty"
                Case 6
                    result = "sixty"
                Case 7
                    result = "seventy"
                Case 8
                    result = "eighty"
                Case 9
                    result = "ninety"
            End Select
            ' Add the ones digit number.
            result = result & " " & Words_1_19(num - tens * 10)
        End If
        Words_1_99 = Trim$(result)
    End Function

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        Dim d As Double
        If Double.TryParse(value.ToString, d) Then
            Return NumbersToWords(CDec(d))
        Else
            Return value
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Return Nothing
    End Function
End Class


Now that we created the class we need to register the xml namespace with the window. The namespace you need to use for this is clr-namespace:NamespaceName. In this case it is the applications name. I am adding the local prefix so we can reference it later.


<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFOneWayBind"
    Title="WPFOneWayBind" Height="300" Width="300"
    >


Now we need to make the converter a resource for the window.


  <Window.Resources>
    <local:NumberToWord x:Key="conv"></local:NumberToWord>
  </Window.Resources>



Right after we set the path for the binding we can specify the converter. The converter is a StaticResource of the window.


      <Label   HorizontalAlignment="Center" DataContext="{Binding ElementName=hscroll, Mode=OneWay}"
               Content="{Binding Path=Value, Converter = {StaticResource conv}}"  />


Here is the windows complete XAML



<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFOneWayBind"
    Title="WPFOneWayBind" Height="300" Width="300"
    >
  <Window.Resources>
    <local:NumberToWord x:Key="conv"></local:NumberToWord>
  </Window.Resources>
    <Grid>
      <StackPanel>
      <ScrollBar Name="hscroll" Maximum="100"  Minimum="1" SmallChange="1" LargeChange="10" Orientation="Horizontal"></ScrollBar>
      <Label   HorizontalAlignment="Center" DataContext="{Binding ElementName=hscroll, Mode=OneWay}"
               Content="{Binding Path=Value, Converter = {StaticResource conv}}"  />
      </StackPanel>
    </Grid>
</Window>




WPF OneWay Binding Part 3


In this part we will bind to a class. We will start off by creating a grid to display the properties of the class. Finally we will show how to get the form to update itself when a value changes in the class.


Lets start off creating a class that shows some info about the computer. Here is the class.

Public Class ComputerInfo

    Public ReadOnly Property UserName() As String
        Get
            Return Environment.UserName
        End Get
    End Property
    Public ReadOnly Property ComputerName() As String
        Get
            Return Environment.MachineName
        End Get
    End Property
    Public ReadOnly Property UpTime() As Integer
        Get
            Return Environment.TickCount
        End Get
    End Property


End Class

Ok lets register the class with the form.

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFOneWayBindToVariable"
    Title="WPFOneWayBindToVariable" Height="300" Width="300"
    >
  <Window.Resources>
    <local:ComputerInfo x:Key="ci"></local:ComputerInfo>
  </Window.Resources>

Now lets create a grid with 2 columns and 3 rows to show the class in.

   <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
      </Grid.RowDefinitions>

Lets put the data in the grid we just created.

      <Label Grid.Column="0" Grid.Row="0" Content="User Name" HorizontalAlignment="Right"/>
      <Label Grid.Column="0" Grid.Row="1" Content="Computer Name" HorizontalAlignment="Right"/>
      <Label Grid.Column="0" Grid.Row="2" Content="Up Time" HorizontalAlignment="Right"/>
      <Label Grid.Column="1"  Grid.Row="0" Content="{Binding Path=UserName}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>
      <Label Grid.Column="1"  Grid.Row="1" Content="{Binding Path=ComputerName}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>
      <Label Grid.Column="1"  Grid.Row="2" Content="{Binding Path=UpTime}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>

To get the form to update itself automatically when a value changes in the class the class has to inherit from DependencyObject. The properties values that can change must be stored in a DependencyProperty. In this class I want the UpTime property to update itself every second with a timer.


Imports System.Windows.Threading

Public Class ComputerInfo
    Inherits DependencyObject

    Public Shared TickCountProperty As DependencyProperty = DependencyProperty.Register("UpTime", GetType(Integer), GetType(ComputerInfo))


    Public Sub New()
        Dim dt As New DispatcherTimer
        AddHandler dt.Tick, AddressOf TimerTick
        With dt
            .Interval = TimeSpan.FromSeconds(1)
            .Start()
        End With
    End Sub

    Public ReadOnly Property UserName() As String
        Get
            Return Environment.UserName
        End Get
    End Property
    Public ReadOnly Property ComputerName() As String
        Get
            Return Environment.MachineName
        End Get
    End Property
    Public ReadOnly Property UpTime() As Integer
        Get
            Return GetValue(TickCountProperty)
        End Get
    End Property

    Public Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs)
        SetValue(TickCountProperty, Environment.TickCount)
    End Sub

End Class



Here is the windows complete XAML

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFOneWayBindToVariable"
    Title="WPFOneWayBindToVariable" Height="300" Width="300"
    >
  <Window.Resources>
    <local:ComputerInfo x:Key="ci"></local:ComputerInfo>
  </Window.Resources>
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
      </Grid.RowDefinitions>
      <Label Grid.Column="0" Grid.Row="0" Content="User Name" HorizontalAlignment="Right"/>
      <Label Grid.Column="0" Grid.Row="1" Content="Computer Name" HorizontalAlignment="Right"/>
      <Label Grid.Column="0" Grid.Row="2" Content="Up Time" HorizontalAlignment="Right"/>
      <Label Grid.Column="1"  Grid.Row="0" Content="{Binding Path=UserName}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>
      <Label Grid.Column="1"  Grid.Row="1" Content="{Binding Path=ComputerName}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>
      <Label Grid.Column="1"  Grid.Row="2" Content="{Binding Path=UpTime}" DataContext="{Binding Source={StaticResource ci}}">
      </Label>
    </Grid>
</Window>



WPF Bind to a Method


In this part we will bind to a method. As we type a number into a textbox the results will be displayed in label below it. For this example we use a class which figures out the area of a circle.


Let's start off with a class which calculates the area of a circle. This class has one function named CalculateArea.

Public Class Area

    Public Function CalculateArea(ByVal Radius As Double) As Double
        Return Math.PI * Radius ^ 2
    End Function
End Class


Now that we have a class set up to calculate the area we need 2 additonal classes. The first needs to inherit from ValidationRule to alert the user if they enter an incorrect value (textbox's border turns red for invalid values). The other need to inherit from IValueConveter to convert the user input from string to double and back again.


Imports System.Windows.Controls
Imports System.Windows.Data

Public Class ValidDouble
    Inherits ValidationRule


    Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As System.Globalization.CultureInfo) As System.Windows.Controls.ValidationResult
        Dim num As Double

        If Double.TryParse(value.ToString, num) Then
            Return New ValidationResult(True, Nothing)
        Else
            Return New ValidationResult(False, "Invalid Number")
        End If
    End Function
End Class


Public Class DoubleToString
    Implements IValueConverter

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        If value IsNot Nothing Then
            Return value.ToString
        Else
            Return Nothing
        End If
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Dim num As Double
        If (value IsNot Nothing) AndAlso Double.TryParse(value.ToString, num) Then
            Return num
        Else
            Return Nothing
        End If
    End Function
End Class

Now that we have the classes we need its time to register the namespaces with the form.


<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFBindToMethod"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="WPFBindToMethod" Height="300" Width="300"
    >

Finally we will use an ObjectDataProvider to bind to the method and register the ValidationRule with the form.


  <Window.Resources>
    <ObjectDataProvider ObjectType="{x:Type local:Area}"
                        MethodName="CalculateArea" x:Key="CircleArea">
      <ObjectDataProvider.MethodParameters>
        <system:Double>0</system:Double>
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

    <local:DoubleToString x:Key="doubleToString" />
    
  </Window.Resources>

The Form's complete XAML



<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFBindToMethod"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="WPFBindToMethod" Height="300" Width="300"
    >
  <Window.Resources>
    <ObjectDataProvider ObjectType="{x:Type local:Area}"
                        MethodName="CalculateArea" x:Key="CircleArea">
      <ObjectDataProvider.MethodParameters>
        <system:Double>0</system:Double>
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

    <local:DoubleToString x:Key="doubleToString" />
    
  </Window.Resources>
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition Width="140"/>
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
      </Grid.RowDefinitions>
      <Label Grid.Row="0"  Grid.Column="0"  HorizontalAlignment="Right">Radius of the Circle:</Label>
      <TextBox Grid.Row="0" Grid.Column="1" Name="tb">
        <TextBox.Text>
          <Binding Source="{StaticResource CircleArea}" Path="MethodParameters[0]"
                   BindsDirectlyToSource="true" UpdateSourceTrigger="PropertyChanged"
                   Converter="{StaticResource doubleToString}">
            <Binding.ValidationRules>
              <local:ValidDouble/>
            </Binding.ValidationRules>
          </Binding>
        </TextBox.Text>
      </TextBox>
      <Label Grid.Row="1"  Grid.Column="0" HorizontalAlignment="Right">Area of the Circle:</Label>
      <Label Grid.Column="1" Grid.Row="1" Content="{Binding Source={StaticResource CircleArea}}"></Label>
    </Grid>
</Window>



1 2 Previous Next