Friday, August 29, 2008

Conditionally Setting Font Color In A WPF TreeView


I wanted to alert my users of validation errors for items in my TreeView by setting the font color to red and then changing the tooltip to display the error message. This is super easy to do with WPF by adding a couple of properties to the classes your TreeView displays. I changed my Info() property to conditionally return the normal tooltip or error message:

Public ReadOnly Property Info() As String

Get

Dim msg As String = ""

If ErrorMsg.Length = 0 Then

msg = ColumnList.Count & " column(s)"

Else

' Table is invalid

msg = ErrorMsg

End If

Return msg

End Get

End Property

Then I added a FontColor property that returns a Brush so the TextBlock.Foreground could bind to it:

Public ReadOnly Property FontColor() As Brush

Get

Dim c As Brush = Brushes.Black

If IsInvalid Then

c = Brushes.Red

End If

Return c

End Get

End Property

Then I change my XAML to bind to the new properties:

ToolTip="{Binding Path=Info}" Foreground="{Binding Path=FontColor}"


Tuesday, August 12, 2008

Using WseWSDL3.exe to generate proxy class for Visual Studio 2008

Our development environment includes a web service MOM that uses WSE 3.0 to provide security, but I discovered from the MSDN forums that Visual Studio 2008 does not have built-in support for WSE like 2005 did. There are a couple of different workarounds, but the cleanest approach seems to be using the WSDL to Proxy Class Tool (wsewsdl3.exe) included with the WSE 3.0 tools – default location: C:\Program Files\Microsoft WSE\v3.0\Tools

I used the following command to generate a proxy class from a WSDL file in the same directory (you can also pass a URL):

wsewsdl3 MyService.wsdl /language:VB /namespace:MyCoolSvc /type:webClient

The /type specifies which class to inherit from. Check out the MSDN documentation for additional details.

Note, that our environment uses a CustomPolicyAssertion to authenticate the request:

Dim cpa As New MyCompany.Web.Services.CustomPolicyAssertion

Dim p As New Microsoft.Web.Services3.Design.Policy

Dim wscp As New Microsoft.Web.Services3.WebServicesClientProtocol

p.Assertions.Add(cpa)

wscp.SetPolicy(p)

wscp.RequestSoapContext.Add("StdUser", "MyApp")

Friday, August 8, 2008

Binding a WPF TreeView to an ObservableCollection

Here’s an example of Binding a WPF TreeView to an ObservableCollection to be able to dynamically add/remove items.  Not the xmlns:local= is set to the Namespace of your WPF project (intellisense will assist):

<Window x:Class="TreeTest"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  xmlns:local="clr-namespace:CodeGen"

  Title="TreeTest" Height="300" Width="300">

    <Grid>

        <TreeView Margin="25,20,130,40" Name="TreeView1" ItemsSource="{x:Static local:TreeTest.BoatList}" >

            <TreeView.ItemTemplate>

                <DataTemplate>

                    <TextBlock Text="{Binding Path=Name}" />

                </DataTemplate>

            </TreeView.ItemTemplate>

        </TreeView>

        <Button Height="23" HorizontalAlignment="Right" Margin="0,50,26,0" Name="Button1" VerticalAlignment="Top" Width="75">Load Items</Button>

        <Button HorizontalAlignment="Right" Margin="0,113,26,126" Name="Button2" Width="75">Change Items</Button>

    </Grid>

</Window>

 

Imports System.Collections.ObjectModel

 

Partial Public Class TreeTest

 

    Public Shared BoatList As New ObservableCollection(Of Boat)

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click

        BoatList.Add(New Boat("FS 338", 19))

        BoatList.Add(New Boat("Hobie 16", 16))

    End Sub

 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button2.Click

        Dim b As Boat = BoatList(0)

        BoatList.Remove(b)

        BoatList.Add(New Boat("Mad River Canoe", 17))

    End Sub

End Class

 

Public Class Boat

 

    Private _name As String

    Public Property Name() As String

        Get

            Return _name

        End Get

        Set(ByVal value As String)

            _name = value

        End Set

    End Property

 

    Private _length As Integer

    Public Property Length() As Integer

        Get

            Return _length

        End Get

        Set(ByVal value As Integer)

            _length = value

        End Set

    End Property

 

    Public Sub New(ByVal name As String, ByVal len As Integer)

        _name = name

        _length = len

    End Sub

 

End Class

 

 

 

CopySourceAsHTML Visual Studio 2008 AddIn

Up until now, the code I've posted has been formatted mainly with the Outlook RTF copy from VS to. After being completely frustrated with that approach (and it's poor formatting quality) I went in search of a better formatter. Enter CopySourceAsHTML AddIn. Download the ZIP

It's worth noting, I found an online code formatter called csharpformat (it also does VB, T-SQL, XML) that makes your code look like this:

Public Sub Finish()
Dim instance As New SendOrPostCallback(AddressOf UpdateList)

Me.Dispatcher.BeginInvoke(DispatcherPriority.Render, instance, Nothing)
End Sub

My code samples should now look like this:

Public Sub Finish()

Dim instance As New SendOrPostCallback(AddressOf UpdateList)

Me.Dispatcher.BeginInvoke(DispatcherPriority.Render, instance, Nothing)

End Sub


Using SUM(CASE) and SQL Date Functions to compute YTD Totals

I needed to generate a report that had your typical YTD, MTD, Current Week, etc. data. This seemed like a perfect time for a SUM(CASE) statement:


SELECT     'Number of Vouchers Processed' AS Query,
SUM(CASE WHEN Form$Status IN ('Completed', 'Rejected') AND
End$Dt <= @EndDt AND End$Dt >= DATEADD(dd, -7, @EndDt)
THEN 1 ELSE 0 END ) AS WeekCount,
SUM(CASE WHEN Form$Status IN ('Completed', 'Rejected') AND
Month(End$Dt) = Month(@EndDt)
THEN 1 ELSE 0 END ) AS MonthCount,
SUM(CASE WHEN Form$Status IN ('Completed', 'Rejected') AND
Year(End$Dt) = Year(@EndDt)
THEN 1 ELSE 0 END ) AS YearCount,
SUM(CASE WHEN Form$Status IN ('Completed', 'Rejected')
THEN 1 ELSE 0 END ) AS TotalCount
FROM bam_TV_Completed AS TRC

Monday, August 4, 2008

Handle Copy/Paste in Hierarchical TreeView

I’m starting to get my head wrapped around the WPF / XAML paradigm, and hadn’t come across too many examples of Copy/Paste functionality so I thought I would share my recent discovery of the ApplicationCommands class.  With it, adding a CommandBinding to receive Copy events for a control like TreeView is trivial.

Private Sub MainWindow_Loaded(sender As System.Object,
    e As System.Windows.RoutedEventArgs) Handles MainWindow.Loaded

 ' Handle Copy/Paste function

 Dim cb As New CommandBinding(ApplicationCommands.Copy,
    AddressOf TableList_Copy)

 TableList.CommandBindings.Add(cb)

End Sub

 

Private Sub TableList_Copy(ByVal sender As Object,
    ByVal e As ExecutedRoutedEventArgs)

  Dim selectNode As Object = TableList.SelectedValue

  If TypeOf selectNode Is DbTable Then

    Clipboard.SetText(CType(selectNode, DbTable).TableName)

  Else

    Clipboard.SetText(CType(selectNode, Column).Name)

  End If

End Sub

My TreeView is bound to a HierarchicalDataTemplate that can contain a collection of Column objects, hence the need to check the type of the TableList.SelectedValue

<TreeView Margin="19,57,0,28" Name="TableList"
HorizontalAlignment
="Left" Width="286"
ItemsSource="{Binding Path=.}"
ItemTemplate
="{StaticResource TableListTemplate}" />

 

<Grid.Resources>

  <DataTemplate x:Key="TableTemplate">

    <TextBlock>

      <TextBlock Text="{Binding Path=Name}" />

      <Run>(</Run>

      <TextBlock Text="{Binding Path=Type}" />

      <Run>)</Run>

    </TextBlock>

  </DataTemplate>

   

  <HierarchicalDataTemplate x:Key="TableListTemplate"

   ItemsSource="{Binding Path=ColumnList}"

    ItemTemplate="{StaticResource TableTemplate}" >

     <TextBlock Text="{Binding Path=TableName}" />

  </HierarchicalDataTemplate>

</Grid.Resources>