简体   繁体   中英

String bound to TextBox is not updating

I've got a TextBox and a search Button which has to be enabled only if the TextBox is not empty.

Since I'm using MVVM Light , I've bound the button to a RelayCommand which has a CanExecute function which just returns a boolean value.

Here's the Button 's code:

<Button Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" Margin="10" VerticalAlignment="Center" BorderThickness="1" Style="{StaticResource ButtonNoPadding}" Command="{Binding SearchCommand}">
    <Rectangle Fill="{StaticResource PhoneForegroundBrush}" Width="40" Height="40" >
        <Rectangle.OpacityMask>
            <ImageBrush ImageSource="../Assets/AppBar/feature.search.png" />
        </Rectangle.OpacityMask>
    </Rectangle>
</Button>

and here's the Command and the property returned by the CanExecute function:

/// <summary>
/// Boolean that enables/disables the search button
/// </summary>
public bool CanSearch
{
    get
    {
        return !string.IsNullOrEmpty(SearchQuery) && NetworkUtils.IsNetworkAvailable;
    }
}

/// <summary>
/// Command used to search for data
/// </summary>
private RelayCommand _searchCommand;
public RelayCommand SearchCommand
{
    get
    {
        return _searchCommand ?? new RelayCommand(ExecuteSearch, () => CanSearch);
    }
}

Now, as you may have noticed, the CanSearch property depends on the lenght of the SearchQuery string.

The problem here is that this string is always null until I go back and load the page again. This means that my text, and my property, is updated only if I reload the page.

I've followed this answer to fix this problem and having my SearchQuery update everytime that the text changes (and not only when it loses focus!) but it still won't work.

Here's my TextBox code:

<TextBox Grid.Row="0" Grid.Column="0" Text="{Binding SearchQuery, Mode=TwoWay}" VerticalAlignment="Center">
    <i:Interaction.Behaviors>
        <utils:UpdateSourceOnTextChangedBehavior/>
    </i:Interaction.Behaviors>
</TextBox>

and here's the attached behavior:

public class UpdateSourceOnTextChangedBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += OnTextChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.TextChanged -= OnTextChanged;
    }

    private void OnTextChanged(object sender, RoutedEventArgs e)
    {
        AssociatedObject.GetBindingExpression(TextBox.TextProperty).UpdateSource();
    }
}

The funny thing is that it actually does what it has to do, because the AssociatedObject.GetBindingExpression(TextBox.TextProperty).UpdateSource(); gets called everytime I change a character in my TextBox .

Of course the SearchQuery property raises all the needed events:

/// <summary>
/// Query used to search in the API
/// </summary>
private string _searchQuery;
public string SearchQuery
{
    get
    {
        return _searchQuery;
    }
    set
    {
        if (_searchQuery == value) return;
        _searchQuery = value;
        RaisePropertyChanged(() => SearchQuery);
        RaisePropertyChanged(() => CanSearch);                
        SearchCommand.RaiseCanExecuteChanged();
    }
}

Any idea?

The line

return _searchCommand ?? new RelayCommand(ExecuteSearch, () => CanSearch);

doesn't set the _searchCommand field. Perhaps making a new RelayCommand is messing something up?

Try this instead:

 return (_searchCommand != null) ? _searchCommand : _searchCommand = new RelayCommand(ExecuteSearch, () => CanSearch);

This lazily creates and sets _searchCommand correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM