1

I am currently implementing a search (more properly "filter") form for my View that uses ApplicationBarIconButtons to drive user interactions with the form: a search button to transition to the VisualState with the form displayed, and one to clear the current filter string value. The textbox that accepts the filter is bound to a property on the ViewModel:

XAML

<toolkit:PhoneTextBox x:Name="txtSearch" Text="{Binding VisitsFilter, Mode=OneWay}" />

ViewModel

private string _visitsFilter;
public string VisitsFilter
{
    get
    {
        return _visitsFilter;
    }
    set
    {
        _visitsFilter = value;
        RaisePropertyChanged("VisitsFilter");
        RebuildVisits();
    }
}

The problem is that ApplicationBarIconButtons don't really have any ability to bind to points on my ViewModel with Commands or similar, so I handle their interactions with it in a code behind handler for its Click event. Doesn't seem like it should be that big a deal... Get the ViewModel from the page's data context and set the value of the bound property:

Code Behind

private VisitsViewModel ViewModel
{
    get
    {
        return this.DataContext as VisitsViewModel;
    }
}

private void abbClear_Click(object sender, EventArgs e)
{
    this.Focus();
    ViewModel.VisitsFilter = string.Empty;
}

If you follow the code above through the setter, you'll see that I set the value of the private string member, then raise the event that the property has changed. I actually have a code behind subscription to this event in my View that's performing other logic about making the "Clear" button visible or not, but the point is it is listening successfully on that event. However, the OneWay binding in the markup above doesn't update the value of the Text property on my PhoneTextBox.

Where's the disconnect here?

lsuarez
  • 4,952
  • 1
  • 29
  • 51
  • Can you share a small repro sample? OneWay binding is the default and if the DataContext and your notification function (in your case `RaisePropertyChanged`) work then it should be fine. – Oren May 30 '13 at 22:11
  • Ironically my attempts to repro a small example are failing as abysmally as the original code. I'll go comment out bits and pieces and see what's going sideways when I have access to it again and get back to you. – lsuarez May 31 '13 at 02:27

1 Answers1

1
  1. It is possible that the method in your setter is taking too long, or doing something that might be messing with the UI thread. Meaning by the time it is released to respond to your PropertyChanged, it missed the opportunity to update...

Try removing RebuildVisits(); from the setter. If that works, and this assumption is correct, then execute RebuildVisits on a different thread.

public string VisitsFilter
{
  get { return _visitsFilter; }
  set { 
         _visitsFilter = value;
         RaisePropertyChanged("VisitsFilter");

         Tasks.StartNew (() => { RebuildVisits();});
       }
    ....

}

2.If it's really a one-way binding that's messing with your updates. Why not make set the TextBox

IsReadOnly = "True" and set the binding to TwoWay

denis morozov
  • 6,236
  • 3
  • 30
  • 45
  • That's gonna be a fun one. It looks like you're on the right track with your first speculation. It just looks like I'm going to have to marshal my RaisePropertyChanged calls back to the invoking thread. – lsuarez May 31 '13 at 20:14
  • It doesn't look like rebuild is running so long it's interfering with the UI thread (it's actually just using an in-memory collection and filtering it based on what gets typed in the text box). I don't set the textbox to read-only because the ViewModel behind is only updated in the event that someone types something in the search box and taps the Enter button to invoke the search, which writes the value to the ViewModel. – lsuarez May 31 '13 at 20:30
  • yeah (to comment 1), makes sense, when I often have to do the same, when I am done processing something from a different thread. I have a static utility method that checks the access to main UI thread and despatches... Utilities.OnUI(() => VisitFilter = 3); – denis morozov Jun 01 '13 at 13:03