0

In my Windows Phone 8 app, I have a ListBox control. This list box contains a grid, which contains a pair of TextBlock (title of the field) and a TextBox (user input) controls. This list is generated based on the results of a service the app connects to. What I need to do is access each textbox within the list, and bring back the value of it. To do this, I have bound a unique ID of each item to the Tag property of the TextBox, and I am using the LostFocus event to capture the user input. Once this has been captured and added to a collection in the code behind, the data is processed when the user clicks a button under the list. This works fine for every item except the last one.

The problem is that the LostFocus doesn't work if the button is clicked. The button click method seems to take precedence over the textbox LostFocus method. So if there is only 1 item in the list, the value isn't recorded. Here is the code:

<ItemsControl x:Name="itmScreen4">
    <TextBlock Margin="0,10,0,10">Fields</TextBlock>
    <ListBox x:Name="lstCustom" ItemsSource="{Binding}" Visibility="Visible">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="grdCustom">                                                          
                <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" x:Name="txtCustTitle" Text="{Binding Name}" Foreground="#4C4C4C" FontSize="18" Margin="0,15,0,0"></TextBlock>           
                <TextBox Tag="{Binding DataID}" x:Name="txtCust" Grid.Row="1" Style="{StaticResource TextBox}" Width="450"  LostFocus="txtCust_LostFocus"></TextBox>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button x:Name="btnSubmit" Content="Submit" Background="#404040"></Button>
</ItemsControl>

For the final item in the list (or if there's only one item in the list), the txtCust_LostFocus method doesn't get called when the btnSubmit method is called. Any ideas of how I can capture that final textbox value?

I have tried some other methods (casting a ListBoxItem and performing a FindName on it, for example), but haven't found anything that works. Google hasn't been much help either. Thanks in advance.

EDIT:

Here is the code behind. I am binding a custom class to the list as below.

Class definition here (I have removed some properties for readabality purposes):

Public Class CustomDataRequest
    Public Sub New()
    End Sub

    Public Property ID As Integer        
    Public Property Name As String        

End Class

Use in the code here:

Public Sub ShowCustomData()          
        Dim CustomDataList As New List(Of CustomDataRequest)()

        For Each item In _CustomDataRequestList
            If item.ID= _CurrentID Then
                CustomDataList.Add(item)
            End If
        Next

        lstCustom.ItemsSource = CustomDataList.ToArray

    End Sub

The txtCust_LostFocus method is just capturing the fields at the minute. Once I can actually get it called, I can then add the data to the collection:

Private Sub txtCust_LostFocus(sender As Object, e As RoutedEventArgs)
        Dim elem = DirectCast(sender, FrameworkElement)
        Dim txt = DirectCast(elem.FindName("txtCust"), TextBox)

        Dim text As String = txt.Text
        Dim tag As String = txt.Tag

    End Sub

The problem is that it never gets called once the button has been tapped:

Protected Sub btnSubmit_Tap(sender As Object, e As Input.GestureEventArgs) Handles btnSubmit.Tap
        ValidateData()

    End Sub
venerik
  • 5,766
  • 2
  • 33
  • 43
odinel
  • 566
  • 1
  • 5
  • 28
  • May be you can add your code behind. That will make it easier to grasp what you are doeing. Next to that, why don't you just bind the `Text` property of the `TextBox` to a property of the class you use for binding `Name` and `DataId`? – venerik Nov 27 '13 at 11:40
  • Thanks for your response. I have added some code to show what I'm doing. Could you please elaborate a bit on your suggestion of binding the text in the textbox to a property? I'm not sure how it will help, as the LostFocus method still won't be called. – odinel Nov 27 '13 at 11:51
  • You should add a property to your `CustomDataRequest` class, e.g. `SomeText` and then bind the `TextBox` to this property by adding this attribute in xaml `Text="{Binding SomeText, Mode=TwoWay}"`. When the user adds a text in the textbox the binding will put that text in your property. You don't need the `LostFocus` handler anymore. – venerik Nov 27 '13 at 12:42
  • I did as you said and the text does indeed bind to the class, which is lees code, so thanks for that. However, the problem is still there, of a fashion. If the textbox is selected when the button is hit, i.e. the user has entered text into the box but has hit the button before clicking of the box, the text doesn't get bound. The button click event still takes precedence over everything else. Any ideas...? Thanks – odinel Nov 27 '13 at 14:00
  • O yes, I forgot. Since your textbox doesn't loose focus the binding source (SomeText) is not updated. You can solve it though. Have a look at the answer to this question: http://stackoverflow.com/questions/4833100/updatesourcetrigger-propertychanged-equivalent-for-a-windows-phone-7-textbox – venerik Nov 27 '13 at 14:15

1 Answers1

0

Here is the answer to this. The TextBox should have TwoWay binding mode set, to bind the text value to a corresponding Value property in the class. It should also have UpdateSourceTrigger set to Explicit for binding efficiency, as detailed here.

Public Class CustomDataRequest
    Public Sub New()
    End Sub

    Public Property ID As Integer        
    Public Property Name As String   
    'New property here
    Public Property Value As String

End Class

Textbox code:

<TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=Explicit}" x:Name="txtCust" Grid.Row="1" BorderBrush="#BBBBBB" Style="{StaticResource TextBox}" Width="450" TextChanged="Textbox_Changed"></TextBox>

In the code behind, the following method should be called from the Textbox TextChanged (translated into VB):

Private Sub Textbox_Changed(sender As Object, e As TextChangedEventArgs)
        Dim txt As TextBox = TryCast(sender, TextBox)           
        Dim bindingExpr As BindingExpression = txt.GetBindingExpression(TextBox.TextProperty)
        bindingExpr.UpdateSource()

    End Sub

This solves the problem of the textbox value not binding when the focus is still on the textbox. Thanks to venerik for the answer to this question.

Community
  • 1
  • 1
odinel
  • 566
  • 1
  • 5
  • 28