views:

304

answers:

1

I'm using an ObjectDataProvider to call a class of with IObservableCollection:

<ObjectDataProvider x:Key="WaitingPatientDS" 
      ObjectType="{x:Type local:clsPatients}">
      <ObjectDataProvider.ConstructorParameters>
          <sys:Boolean>True</sys:Boolean>
      </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

clsPatient grabs the data and fills the collection. It also uses a timer to poll the requery the database on interval.

Question: how do I create an event for StartPoll and EndPoll in the clsPatient, and more importantly, how do I bubble those events up to the codebehind of my WPF Window?

A: 

I'm not clear on what is connecting to whom and how, so let me tell you how I'd do it.

ODP constructs an instance of clsPatients, which contains a "collection" filled with "data".

public class clsPatients, INotifyPropertyChanged
{
  public IBindingList Data {get;private set;}
  private DispatcherTimer _timer;

  public ClsPatients()
  {
    _timer = new DispatcherTimer();
    _timer.Interval = TimeSpan.FromMilliseconds(someInterval);
    _timer.Tick += DispatcherTimerTick;
    _timer.Start();
  }
  /* etc etc */
}

clsPatients also has a DispatcherTimer which, on a regular interval updates the Data property and fires PropertyChanged

public void DispatcherTimerTick(object sender, EventArgs e)
{
  Data = new BindingList(Repository.GetMyDataLol());
  // standard event firing method here, move along:
  OnPropertyChanged("Data");
}

In the UI, I'd bind against this collection thusly (this may be bug free, or maybe its not):

<ItemsControl 
  ItemsSource="{Binding Data Source={StaticResource WaitingPatientDS}}">
  <ItemsControl.Resources>  
    <DataTemplate>
      <!-- yadda -->

How this works to update the UI when Data is updated:

  1. clsPatient is provided to the ItemsControl by the ObjectDataProvider
  2. ItemsControl uses the WPF binding infrastructure to bind against the Data property of the instance provided by the ODP.
  3. The DispatcherTimer (operating on the UI thread) of the clsPatient updates Data and fires PropertyChanged, which notifies all bindings subscribing to this event that the property has ironically enough changed
  4. The binding takes over and refreshes the ItemsControl


To show an animation that indicates loading is in progress, add another property to clsPatient called Loading:

 public Visibility Loading{get;private set}

and update the timer tick event:

public void DispatcherTimerTick(object sender, EventArgs e)
{
  Loading = Visibility.Visible;
  OnPropertyChanged("Loading");
  Data = new BindingList(Repository.GetMyDataLol());
  OnPropertyChanged("Data");
  Loading = Visibility.Hidden;
  OnPropertyChanged("Loading");
}

then, in the ui, bind your indicator's Visibility property to Loading:

<Grid DataContext="{Binding Data Source={StaticResource WaitingPatientDS}}">
  <ItemsControl 
    ItemsSource="{Binding Data}">
    <ItemsControl.Resources>  
      <DataTemplate>
        <!-- yadda -->
  </ItemsControl>
  <Image Source="hurf.jpg" Visibility="{Binding Loading}"
    HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

the Image (or whatever other control you want to use) appears when Loading is set to Visible and goes away when its set to Hidden. So you can show the image when you're loading data.


If the UI isn't updating, the process is probably blocking the UI as its executing in the UI thread.

To fix this, run a System.Threading.Timer instead of a DispatcherTimer. STT runs on a background thread other than the UI. In the timer's callback method, use the dispatcher to update the ui (the Invoke methods may be buggy; check the docs on Dispatcher.Invoke):

public void UpdateData(Object stateInfo)
{
  var disp = Dispatcher.CurrentDispatcher();
  Loading = Visibility.Visible;
  disp.Invoke(() => { OnPropertyChanged("Loading");});
  // optional sleep here
  Data = new BindingList(Repository.GetMyDataLol());
  disp.Invoke(() => { OnPropertyChanged("Data");});
  Loading = Visibility.Hidden;
  disp.Invoke(() => { OnPropertyChanged("Loading");});
}
Will
Thanks, but let me elaborate:I don't care about properties changing. I want two events to fire in the Timer Tick. One before the data pull and one after--let's call those "BeforePoll" and "AfterPoll". Then on the GUI, I want to trap those events or bind to them somehow so that I can turn on and off and animated cycle gif (ala, the AJAX look), so that the user knows something is happening behind the scenes...Thanks again for your help...I get the gist, but just need more concrete examples...
Ok...very close...you are helping tremendously, but it looks like I'm never receiving the first OnPropertyChanged notification where the Visibility is "Visible". I even put a 1 sec sleep after the data load to make the animation stay up longer...can you think of what I'm doing wrong?
Hmmm.... this is happening in the UI thread and so is probably blocking the UI from updating...
Will