views:

1978

answers:

5

I have a Silverlight 2 application that validates data OnTabSelectionChanged. Immediately I began wishing that UpdateSourceTrigger allowed more than just LostFocus because if you click the tab without tabbing off of a control the LINQ object is not updated before validation.

I worked around the issue for TextBoxes by setting focus to another control and then back OnTextChanged:

Private Sub OnTextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs)
    txtSetFocus.Focus()
    sender.Focus()
End Sub

Now I am trying to accomplish the same sort of hack within a DataGrid. My DataGrid uses DataTemplates generated at runtime for the CellTemplate and CellEditingTemplate. I tried writing the TextChanged="OnTextChanged" into the TextBox in the DataTemplate, but it is not triggered.

Anyone have any ideas?

A: 

I know it's old news... but I got around this by doing this:

Text="{Binding Path=newQuantity, UpdateSourceTrigger=PropertyChanged}"

Chu
Chu, from everything I have read there is no PropertyChanged choice for the UpdateSourceTrigger in SL2 or SL3.?
Dave Lowther
PropertyChanged is value for UpdateSourceTrigger in WPF.
sparks
A: 

Dont suppose there was ever a Silverlight workaround actually established for this was there?

I'm kinda stuck with this myself.

Matthew Black
i think the move to SL3 cleared it up, can't recall for sure.
Dave Lowther
no it didn't - still no PropertyChanged even in SL4
Simon_Weaver
A: 

This blog post shows how to update the source of a textbox explicitly using attached property: http://www.thomasclaudiushuber.com/blog/2009/07/17/here-it-is-the-updatesourcetrigger-for-propertychanged-in-silverlight/

You could easily modify it to work with other controls as well...

murki
A: 

Hi,

I ran into this same problem using MVVM and Silverlight 4. The problem is that the binding does not update the source until after the textbox looses focus, but setting focus on another control doesn't do the trick.

I found a solution using a combination of two different blog posts. I used the code from Patrick Cauldwell's DefaultButtonHub concept, with one "SmallWorkaround" from SmallWorkarounds.net

http://www.cauldwell.net/patrick/blog/DefaultButtonSemanticsInSilverlightRevisited.aspx

www.smallworkarounds.net/2010/02/elementbindingbinding-modes.html

My change resulted in the following code for the DefaultButtonHub class:

public class DefaultButtonHub
{
    ButtonAutomationPeer peer = null;

    private void Attach(DependencyObject source)
    {
        if (source is Button)
        {
            peer = new ButtonAutomationPeer(source as Button);
        }
        else if (source is TextBox)
        {
            TextBox tb = source as TextBox;
            tb.KeyUp += OnKeyUp;
        }
        else if (source is PasswordBox)
        {
            PasswordBox pb = source as PasswordBox;
            pb.KeyUp += OnKeyUp;
        }
    }

    private void OnKeyUp(object sender, KeyEventArgs arg)
    {
        if (arg.Key == Key.Enter)
            if (peer != null)
            {
                if (sender is TextBox)
                {
                    TextBox t = (TextBox)sender;
                    BindingExpression expression = t.GetBindingExpression(TextBox.TextProperty);
                    expression.UpdateSource();
                }
                ((IInvokeProvider)peer).Invoke();
            }
    }

    public static DefaultButtonHub GetDefaultHub(DependencyObject obj)
    {
        return (DefaultButtonHub)obj.GetValue(DefaultHubProperty);
    }

    public static void SetDefaultHub(DependencyObject obj, DefaultButtonHub value)
    {
        obj.SetValue(DefaultHubProperty, value);
    }

    // Using a DependencyProperty as the backing store for DefaultHub.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DefaultHubProperty =
        DependencyProperty.RegisterAttached("DefaultHub", typeof(DefaultButtonHub), typeof(DefaultButtonHub), new PropertyMetadata(OnHubAttach));

    private static void OnHubAttach(DependencyObject source, DependencyPropertyChangedEventArgs prop)
    {
        DefaultButtonHub hub = prop.NewValue as DefaultButtonHub;
        hub.Attach(source);
    }

}

This should be included in some sort of documentation for Silverlight :)

Ben Brodie
A: 

You can do it with a behavior applied to the textbox too

// xmlns:int is System.Windows.Interactivity from System.Windows.Interactivity.DLL)
// xmlns:behavior is your namespace for the class below
<TextBox Text="{Binding Description,Mode=TwoWay,UpdateSourceTrigger=Explicit}">
    <int:Interaction.Behaviors>
       <behavior:TextBoxUpdatesTextBindingOnPropertyChanged />
    </int:Interaction.Behaviors>
</TextBox>


public class TextBoxUpdatesTextBindingOnPropertyChanged : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.TextChanged += new TextChangedEventHandler(TextBox_TextChanged);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.TextChanged -= TextBox_TextChanged;
    }

    void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var bindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
        bindingExpression.UpdateSource();
    }
}
Simon_Weaver