Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference in xaml terms used for binding

I am a beginner with xaml (for MVVM APPROACH) using Silverlight. I read several documents and am a bit confused about it all. I would really appreciate if someone could explain the difference between the following.

Suppose my XAML is:

  xmlns:viewmodel="clr-namespace:smallMVVM"
  ......
  ......  
 <UserControl.Resources>
        <viewmodel:ViewModel x:Key="ViewModel"/>
        <viewmodel:DatetimeToDateConverter x:Key="MyConverter"/>
 </UserControl.Resources>

Now what is the difference between:

  1. I mean in MainPage.cs if I do "this.DataContext = new ViewModel();" . And in MainPage.xaml if I do the following <Grid DataContext="{Binding Source={StaticResource ViewModel}}">. Is there any difference between the two ?

  2. Somewhere I saw ItemsSource="{StaticResource customers}" in some example. How is ItemSource different from DataContext. Whereas I can see in the example (1) that I have same inside the Binding of DataContext (please see this: Source={StaticResource ViewModel} and in (2) it is replaced with customers). How are the two different?

  3. Sometimes I also see directly ItemsSource="{Binding Students}" there is no StaticResource inside. How is it different from with StaticResource?

  4. Some examples have simply Binding="{Binding Name}".

  5. How are SelectedItem and SelectedValue different?

Could someone please explain them with a small and simple example ? On internet search there are typical examples for a beginner to understand.

like image 871
Sss Avatar asked Nov 10 '22 05:11

Sss


1 Answers

1) Technically there is no difference between the two declarations of the Data Context I like to do it in the code-behind, which looks like this:

Partial Public Class MainPage
    Inherits UserControl

    Private _viewModel As TestViewModel

    Public Sub New()
        InitializeComponent()
        _viewModel = TryCast(Resources("TheViewModel"), TestViewModel)
        Me.DataContext = _viewModel
    End Sub
End Class

2)You don't want to set your ItemsSource to a Static Page Resource, you want to set it to a Property in your ViewModel. Below is a sample View and ViewModel, notice the Inherits and Impelments on the VM, These allow your VM to tell your View that properties have changed, and to reload the property.

View:

<UserControl x:Class="SilverlightTestApp.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:ModelViewModel="clr-namespace:SilverlightTestApp"  >

<UserControl.Resources>
    <ModelViewModel:TestViewModel x:Key="TheViewModel" />
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource TheViewModel}">
    <ItemsControl ItemsSource="{Binding SampleCollection}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}"></TextBlock>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

ViewModel:

Imports System.ComponentModel
Imports System.Collections.ObjectModel
Public Class TestViewModel
    Inherits DependencyObject
    Implements System.ComponentModel.INotifyPropertyChanged
    Implements INotifyDataErrorInfo

    Private _model As TestModel

    Sub New()
        Me.New(New TestModel)
    End Sub

    Public Sub New(ByVal model As TestModel)
        _model = model

        _sampleCollection = New ObservableCollection(Of String)
        _sampleCollection.Add("one")
        _sampleCollection.Add("two")
        _sampleCollection.Add("three")
        _sampleCollection.Add("four")

    End Sub

    Private _sampleCollection As ObservableCollection(Of String)
    Public Property SampleCollection As ObservableCollection(Of String)
        Get
            Return _sampleCollection
        End Get
        Set(value As ObservableCollection(Of String))             
            If value IsNot Nothing Then
                _sampleCollection = value
            End If
            Me.OnPropertyChanged("SampleCollection")

        End Set
    End Property

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged

    Protected errors As New Dictionary(Of String, List(Of String))

    Protected Sub OnPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
    End Sub

    ' #Region " Validation Plumbing"
    ' Adds the specified error to the errors collection if it is not 
    ' already present, inserting it in the first position if isWarning is 
    ' false. Raises the ErrorsChanged event if the collection changes. 
    Public Sub AddError(ByVal propertyName As String, ByVal [error] As String,
                        ByVal isWarning As Boolean)

        If Not errors.ContainsKey(propertyName) Then _
            errors(propertyName) = New List(Of String)()

        If Not errors(propertyName).Contains([error]) Then
            If isWarning Then
                errors(propertyName).Add([error])
            Else
                errors(propertyName).Insert(0, [error])
            End If
            RaiseErrorsChanged(propertyName)
        End If

    End Sub

    ' Removes the specified error from the errors collection if it is
    ' present. Raises the ErrorsChanged event if the collection changes.
    Public Sub RemoveError(ByVal propertyName As String, ByVal [error] As String)

        If errors.ContainsKey(propertyName) AndAlso
            errors(propertyName).Contains([error]) Then

            errors(propertyName).Remove([error])
            If errors(propertyName).Count = 0 Then errors.Remove(propertyName)
            RaiseErrorsChanged(propertyName)

        End If

    End Sub
    Public Sub RemoveError(ByVal propertyName As String)

        If errors.ContainsKey(propertyName) Then

            errors.Remove(propertyName)
            RaiseErrorsChanged(propertyName)

        End If

    End Sub

    Public Sub RaiseErrorsChanged(ByVal propertyName As String)
        OnPropertyChanged("HasErrors")
        RaiseEvent ErrorsChanged(Me,
            New DataErrorsChangedEventArgs(propertyName))
    End Sub

    Public Event ErrorsChanged As EventHandler(Of DataErrorsChangedEventArgs) _
        Implements INotifyDataErrorInfo.ErrorsChanged

    Public Function GetErrors(ByVal propertyName As String) _
        As System.Collections.IEnumerable _
        Implements INotifyDataErrorInfo.GetErrors

        If (String.IsNullOrEmpty(propertyName) OrElse
            Not errors.ContainsKey(propertyName)) Then Return Nothing
        Return errors(propertyName)

    End Function

    Public ReadOnly Property HasErrors As Boolean _
        Implements INotifyDataErrorInfo.HasErrors
        Get
            Return errors.Count > 0
        End Get
    End Property

End Class

The key piece above is Me.OnPropertyChanged("SampleCollection") which tells the View to update the property it is bound to.

A note on architecture, if you are building an application with multiple Views and ViewModels, create a ViewModelBase and have it inherit DependencyObject and Implement INotifyPropertyChanged, then all of your real view models can Inherit from the ViewModelBase.

I also created a class called TestModel that is used in the VM, but left it empty. The model is where you put the code to talk to the DB, or what I do, call a WCF Service that talks to my DB.

5) Finally, the SelectedItem is the actual object within the ItemSource that is selected, whereas SelectedValue is the value of SelectedValuePath. In the example above, I've created a simple collection of String, but say you have a collection of custom objects that have multiple properties, you can specify the SelectedValuePath as one of those properties. The SelectedItem would return the entire object.

like image 88
Brian Avatar answered Nov 14 '22 23:11

Brian