MVVM Example with WCF Services

12 posts, 0 answers
  1. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 26 May 2011 Link to this post

    I have followed the MVVM Chart example and have it working great in my own project. I am now trying to load the chart with my data rather than the hard-coded data in the example. My problem though is that I am using WCF services which must be called asynch so within my viewmodel the Data property is being accessed before the asynch callback has occured and there is nothing in my data object.

    Imports Telerik.Windows.Controls
      
        Public Class ExampleViewModel
      
            Private _costIndexData As List(Of Dictionary(Of String, String))
      
            Public  Property TinNumber As String
            Public  Property SubTinSequenceNumber As String    
      
            Public Sub New()
      
                BeginRequest()
      
            End Sub
      
            Private Sub BeginRequest()
      
                Dim lProviderService As New ProviderService.ProviderDashboardServiceClient()
      
                AddHandler lProviderService.GetCostIndexSummaryDataCompleted, AddressOf CostIndexSummaryDataCompletedCallback
      
                lProviderService.GetCostIndexSummaryDataAsync(TinNumber, SubTinSequenceNumber)
      
            End Sub
      
            Private Sub CostIndexSummaryDataCompletedCallback(ByVal sender As Object, ByVal e As ProviderService.GetCostIndexSummaryDataCompletedEventArgs)
              
                _costIndexData = e.Result
      
            End Sub
      
            Public ReadOnly Property Data() As List(Of DataViewModel)
      
                Get
      
                    Dim dataList As New List(Of Data)() 
      
                    For Each lRecord As Dictionary(Of String, String) In _costIndexData
      
                       dataList.Add(New Data(lRecord("ServiceCategory"), lRecord("CostIndex")))
      
                    Next
      
                    Dim modelList As New List(Of DataViewModel)()
      
                    For Each dataItem As Data In dataList
                        modelList.Add(New DataViewModel(dataItem))
                    Next
      
                    Return modelList
      
                End Get
      
            End Property
      
            Public ReadOnly Property ApplicationThemeAwareForeground() As Brush
                Get
                    If Not StyleManager.ApplicationTheme Is Nothing _
                        AndAlso StyleManager.ApplicationTheme.[GetType]() Is GetType(Expression_DarkTheme) Then
                        Return New SolidColorBrush(Color.FromArgb(255, 204, 204, 204))
                    End If
      
                    Return New SolidColorBrush(Color.FromArgb(255, 0, 0, 0))
                End Get
            End Property
      
        End Class

    How do I go about getting the data from my WCF service loaded before the Data property is accessed? Also, you will notice I have two public properties which are needed to actually get my data. How do I go about passing those values in to my viewmodel?

    Thank you!
  2. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 31 May 2011 Link to this post

    Hi jfkrueger,

    The reason why the RadChart doesn't show the new data is because it cannot know when its data source has changed. You can use the PropertyChanged event, provided by the INotifyPropertyChanged interface, to notify the framework that the new data has arrived and it must re-read it. You can convert your _costIndexData field to a property that throws this event, and RadChart will rebind itself automatically. Your property can look like this:

    Public Property CostIndexData() As List(Of Dictionary(Of String, String))
        Get
            Return _costIndexData
        End Get
        Set(ByVal value As List(Of Dictionary(Of String, String)))
            _costIndexData = value
            ' Call NotifyPropertyChanged when the property is updated
            NotifyPropertyChanged("CostIndexData")
        End Set
    End Property

    Now when you want to set the new data to your RadChart use this new property instead of the backing field. Also make sure you are binding your ItemsSource property of your chart to the new notifiable property.

    Hope this helps!


    Greetings,
    Yavor Ivanov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 03 Jun 2011 Link to this post

    Thank you.

    Yes that definitely helps but now I am getting the attached error when trying to view my MainPage.xaml file in the designer.

    Data.vb:

    Imports System.ComponentModel
      
    Public Class Data
        Implements INotifyPropertyChanged
      
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 
      
        Private _serviceCategory As String
        Private _costIndex As Double
      
        Public Sub New(ByVal serviceCategory As String, ByVal costIndex As Double)
            Me._serviceCategory = serviceCategory
            Me._costIndex = costIndex
        End Sub
      
        Public Property ServiceCategory() As String
      
            Get
                Return Me._serviceCategory
            End Get
      
            Set(ByVal value As String)
      
                If String.Compare(Me._serviceCategory, Value, StringComparison.CurrentCultureIgnoreCase) = 0 Then
                    Return
                End If
      
                Me._serviceCategory = Value
              
            End Set
      
        End Property
      
        Public Property CostIndex() As Double
            Get
                Return Me._costIndex
            End Get
            Set(ByVal value As Double)
                If Me._costIndex = Value Then
                    Return
                End If
      
                Me._costIndex = Value
            End Set
        End Property
      
        Protected Overridable Sub OnPropertyChanged(propertyName As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
      
    End Class

    DataViewModel.vb

    Imports System.ComponentModel
    Imports System.Windows.Media
      
        Public Class DataViewModel
            Implements INotifyPropertyChanged
      
            Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 
      
            Private _data As Data
            Private _populationColor As Brush
      
            Public Sub New(data As Data)
                Me._data = data
                AddHandler data.PropertyChanged, AddressOf HandleDataPropertyChanged
                Me.UpdatePopulationColor()
            End Sub
      
            Public ReadOnly Property Data() As Data
                Get
                    Return _data
                End Get
            End Property
      
            Public Property PopulationColor() As Brush
                Get
                    Return _populationColor
                End Get
                Private Set
                    If Object.Equals(Me._populationColor, value) Then
                        Return
                    End If
      
                    Me._populationColor = value
                    Me.OnPropertyChanged("PopulationColor")
                End Set
            End Property
      
            Private Sub HandleDataPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
                If e.PropertyName = "Population" Then
                    Me.UpdatePopulationColor()
                End If
            End Sub
      
      
            Protected Overridable Sub OnPropertyChanged(propertyName As String)
                RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
            End Sub
      
            Private Function CreateBrush(color As String) As Brush
                Return New SolidColorBrush(Me.GetColorFromHexString(color))
            End Function
      
            Private Function GetColorFromHexString(s As String) As Color
                s = s.Replace("#", String.Empty)
      
                Dim a As Byte = System.Convert.ToByte(s.Substring(0, 2), 16)
                Dim r As Byte = System.Convert.ToByte(s.Substring(2, 2), 16)
                Dim g As Byte = System.Convert.ToByte(s.Substring(4, 2), 16)
                Dim b As Byte = System.Convert.ToByte(s.Substring(6, 2), 16)
                Return Color.FromArgb(a, r, g, b)
            End Function
      
            Private Sub UpdatePopulationColor()
                If Me.Data.CostIndex < 1 Then
                    Me.PopulationColor = Me.CreateBrush("#00CD00")
                Else
                    Me.PopulationColor = Me.CreateBrush("#EE0000")
                End If
            End Sub
      
        End Class


    ExampleViewModel.vb

    #Region "Imports"
      
    Imports System.ComponentModel
      
    #End Region
      
    Public Class ExampleViewModel
        Implements INotifyPropertyChanged 
      
        #Region "Public Events"
      
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      
        #End Region
      
        Private _costIndexData As List(Of DataViewModel)
      
        #Region "Public Properties"
      
        Public Property TinNumber As String
        Public Property SubTinSequenceNumber As String
      
        #End Region
      
        Public Sub New()
      
            BeginRequest()
      
        End Sub
      
        Public Property CostIndexData As List(OF DataViewModel)
            Get
                Return _costIndexData
            End Get
            Set(ByVal value As List(Of DataViewModel))
                _costIndexData = value
                ' Call NotifyPropertyChanged when the property is updated 
                NotifyPropertyChanged("CostIndexData")
            End Set
        End Property 
      
        Private Sub BeginRequest()
      
            Dim lProviderService As New ProviderService.ProviderDashboardServiceClient()
      
            AddHandler lProviderService.GetCostIndexSummaryDataCompleted, AddressOf CostIndexSummaryDataCompletedCallback
      
            lProviderService.GetCostIndexSummaryDataAsync(TinNumber, SubTinSequenceNumber)
      
        End Sub
      
        Private Sub NotifyPropertyChanged(ByVal info As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
        End Sub
      
        Private Sub CostIndexSummaryDataCompletedCallback(ByVal sender As Object, ByVal e As ProviderService.GetCostIndexSummaryDataCompletedEventArgs)
              
            Dim lRecords As List(Of Dictionary(Of String, String)) = e.Result 
            Dim lDatalist As New List(Of Data)
      
            For Each lRecord As Dictionary(Of String, String) In lRecords
      
                lDatalist.Add(New Data(lRecord("ServiceCategory").ToString.Trim, lRecord("CostIndex")))
      
            Next
      
            Dim lModelList As New List(Of DataViewModel)
      
            For Each lDataItem As Data In lDatalist
      
                lModelList.Add(New DataViewModel(lDataItem))
      
            Next
      
            CostIndexData = lModelList 
      
        End Sub 
      
      
      
    End Class

    MainPage.xaml

    <UserControl x:Class="Ebms.Silverlight.Controls.MainPage"
            mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
            xmlns:Example="clr-namespace:MyCompany.Silverlight.Controls">
      
        <UserControl.DataContext>
            <Example:ExampleViewModel />
        </UserControl.DataContext>
      
      
        <UserControl.Resources>
      
            <Style x:Key="CustomStyle" TargetType="telerik:Bar">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="telerik:Bar">
                            <Canvas>
                                <Rectangle x:Name="PART_DefiningGeometry" 
                                       Height="{TemplateBinding ItemActualHeight}"
                                       Width="{TemplateBinding ItemActualWidth}"
                                       Fill="{Binding DataItem.PopulationColor}" />
                                <Canvas.RenderTransform>
                                    <ScaleTransform x:Name="PART_AnimationTransform" ScaleY="0" />
                                </Canvas.RenderTransform>
                            </Canvas>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
      
            <Style x:Key="CustomLabelStyle" TargetType="telerik:SeriesItemLabel">
                <Setter Property="HorizontalContentAlignment" Value="Center" />
                <Setter Property="Padding" Value="2,0" />
                <Setter Property="IsHitTestVisible" Value="False"/>
                <Setter Property="Template" >
                    <Setter.Value>
                        <ControlTemplate TargetType="telerik:SeriesItemLabel">
                            <Canvas x:Name="PART_MainContainer">
                                <Path                            
                                       Visibility="{TemplateBinding ConnectorVisibility}"
                                       Style="{TemplateBinding ConnectorStyle}"
                                       Stroke="{TemplateBinding Stroke}"
                                       StrokeThickness="{TemplateBinding StrokeThickness}">
                                    <Path.Data>
                                        <PathGeometry >
                                            <PathGeometry.Figures>
                                                <PathFigure x:Name="PART_Connector">
                                                    <PathFigure.Segments>
                                                        <PolyLineSegment />
                                                    </PathFigure.Segments>
                                                </PathFigure>
                                            </PathGeometry.Figures>
                                        </PathGeometry>
                                    </Path.Data>
                                </Path>
                                <Border x:Name="PART_TextContainer"
                                        Style="{TemplateBinding LabelStyle}"
                                        BorderBrush="Transparent"
                                        Background="Transparent">
                                    <TextBlock Foreground="Black"
                                               TextAlignment="{TemplateBinding HorizontalContentAlignment}"
                                               Margin="0"
                                               Text="{TemplateBinding Content}" />
                                </Border>
                            </Canvas>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
      
        </UserControl.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
      
      
            <telerik:RadChart x:Name="RadChart1" ItemsSource="{Binding CostIndexData}">
                    <telerik:RadChart.SeriesMappings>
                        <telerik:SeriesMapping>
                            <telerik:SeriesMapping.SeriesDefinition>
                                <telerik:BarSeriesDefinition ItemStyle="{StaticResource CustomStyle}"
                                                             SeriesItemLabelStyle="{StaticResource CustomLabelStyle}"
                                                             ItemLabelFormat="#Y{0.}">
                                    <telerik:BarSeriesDefinition.LabelSettings>
                                        <telerik:BarLabelSettings LabelDisplayMode="MidPoint" Distance="0" />
                                    </telerik:BarSeriesDefinition.LabelSettings>
                                </telerik:BarSeriesDefinition>
                            </telerik:SeriesMapping.SeriesDefinition>
      
                            <telerik:ItemMapping FieldName="Data.CostIndex" DataPointMember="YValue" />
                            <telerik:ItemMapping FieldName="Data.ServiceCategory" DataPointMember="XCategory" />
                        </telerik:SeriesMapping>
                    </telerik:RadChart.SeriesMappings>
      
                    <telerik:RadChart.DefaultView>
                        <telerik:ChartDefaultView ChartLegendPosition="Bottom">
                            <telerik:ChartDefaultView.ChartTitle>
                                <telerik:ChartTitle Content="Population change (average annual change, thousand)" />
                            </telerik:ChartDefaultView.ChartTitle>
                            <telerik:ChartDefaultView.ChartArea>
                                <telerik:ChartArea>
                                    <telerik:ChartArea.AxisX>
                                        <telerik:AxisX MajorTicksVisibility="Collapsed" />
                                    </telerik:ChartArea.AxisX>
                                    <telerik:ChartArea.AxisY>
                                        <telerik:AxisY AutoRange="False" MinValue="-7000" MaxValue="7000" Step="1000" 
                                                       MinorTicksVisibility="Collapsed"
                                                       MajorTicksVisibility="Collapsed" />
                                    </telerik:ChartArea.AxisY>
                                </telerik:ChartArea>
                            </telerik:ChartDefaultView.ChartArea>
                    </telerik:ChartDefaultView>
                    </telerik:RadChart.DefaultView>
                </telerik:RadChart>
              
        </Grid>
      
    </UserControl>

    The error is pointing to the line:

    Dim

     

     

    lRecords As List(Of Dictionary(Of String, String

    )) = e.Result

    In the CostIndexSummaryDataCompletedCallback method of the ExampleViewModel class.

    I know I must be doing something wrong but I can't tell what. Help!!

    Thanks!

     

     

  4. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 03 Jun 2011 Link to this post

    It appears that the error only occurs in the designer, which also causes my visual studio 2010 to crash if left open for any amount of time. It looks like the data is binding correctly though which is awesome! My only question now is how to show the values as decimals rather than whole numbers and how to get rid of that error in the designer.

    Thank you!
  5. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 06 Jun 2011 Link to this post

    Okay I believe I have everything figured out but the error in the designer is killing me. I can't even work on the xaml anymore because if I have it open for more than 30 seconds visual studio crashes and I have to reopen my entire solution. Could this be beacuse I am calling WCF services on another machine? I have it all working when it runs but the designer keeps crashing.

    Thank you!
  6. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 08 Jun 2011 Link to this post

    Hello jfkrueger,

    It seems that the problem that you are experiencing is not connected directly to telerik products, but rather to a problem in VS when the designer is trying to connect to a web service. The solution is to check if the code is running under the context of a designer and if so not to connect to the web service.

    I have attached a sample application that demonstrates how you can find out if the code is running under the context of a designer to change the background of the page.

    All the best,
    Yavor Ivanov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  7. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 08 Jun 2011 Link to this post

    I agree, it's a Visual Studio problem. I will try what you have suggested and let you know if that helps. I have already updated my options though to "Always show full XAML", so the designer never shows anymore, yet it still crashes constantly. Is the designer still being loaded in the background or something?

    Thanks again, I will let you know if this helps or not.
  8. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 08 Jun 2011 Link to this post

    I did what was suggested, opened up the designer and the error is no longer there. Then Visual Studio crashed again after about 30 seconds.
  9. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 13 Jun 2011 Link to this post

    Hello,

    Can you please change the constructor of your ExampleViewModel so that it doesn't call BeginRequest, but instead initializes your data using sample data. If the designer doesn't crash then I am afraid that the problem is Visual Studio related. In such case its best that you look for solution at MSDN and user communities.

    Greetings,
    Yavor Ivanov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  10. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 14 Jun 2011 Link to this post

    Hi,

    Thank you, I will try. To clarify though it didn't start happening until I hooked it up to the WCF Service. It also doesn't happen on the gauge controls and those are hoooked up to WCF (and i'm not even detecting the environment). I do think that vs 2010 is incredibly buggy, I have had so many problems with it I am longing for vs 2008.
  11. Yavor
    Admin
    Yavor avatar
    401 posts

    Posted 17 Jun 2011 Link to this post

    Hello jfkrueger,

    Alternatively you can try using Telerik RadDomainDataSource which can make your life easier when using WCF RIA services. This blog post can be useful as it contains a sample service, code and step by step explanations.

    Hope this helps!

    Greetings,
    Yavor Ivanov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  12. jfkrueger
    jfkrueger avatar
    269 posts
    Member since:
    Jul 2012

    Posted 27 Jun 2011 Link to this post

    Thanks, I'll have to look into WCF RIA services. For this project I already have a ton of WCF services deployed that gave me exactly what I needed and didn't really want to recreate everything just for a silverlight app.
Back to Top