views:

892

answers:

2

Hi, I have a data navigation user control in Silverlight which opens a child window where the user can enter search criteria and when they press 'Apply' it's suppose to update the bound property in the ViewModel (MVVM pattern.)

The links are: SearchDialog <--> DataNavigator <--> MyView <--> MyViewModel

The dependency property in SearchDialog seems to work, when I set its value, it shows up in DataNavigator; however when the dependency property changes, no notification seems to be sent from DataNavigator to MyView/MyViewModel.

SearchDialog derives from ChildWindow:

public string Search
{
 get { return (string)GetValue(SearchProperty); }
 set { SetValue(SearchProperty, value); }
}

public static readonly DependencyProperty SearchProperty =
 DependencyProperty.Register("Search", typeof(string), typeof(SearchDialog),
 new PropertyMetadata(null));

DataNavigator derives from UserControl:

public Binding Search { get; set; }

private void DataNavigator_Loaded(object sender, Windows.RoutedEventArgs e)
{
 if (Search != null)
  this._searchDialog.SetBinding(SearchDialog.SearchProperty, Search);
}

MyView derives from SilverlightFX.UserInterface.Navigation.Page:

<DataNavigator MovePreviousAction="$model.MovePrevious()"
               CurrentIndex="{Binding CurrentIndex, Mode=TwoWay}"
               MoveNextAction="$model.MoveNext()"
               SaveAction="$model.SaveChanges()"
               IsLoading="{Binding IsLoading, Converter={StaticResource VisibilityConverter}}"
               Search="{Binding SearchString, Mode=TwoWay}"/>

MyViewModel derives from ViewModel:

public string SearchString
    {
     get { return this._search; }

  set
  {
   if(value != this._search)
   {
    this._search = value;
    this.RaisePropertyChanged("SearchString");
   }
  }
 }

I've been trying for hours to find the problem but haven't had any success; anyone see the issue? Thanks in advance,

+1  A: 

Not sure if that Binding property in the middle will work since you're trying to bind it to a property of type string.

Since you're already using some of Nikhil's stuff, you might want to take a look at how he uses Tasks to handle dialogs/child windows while still keeping the MVVM paradigm in place.

Bryant
A: 

Bryant's solution looks like the right way to go but I still had some problems. I did end up getting this to work using the following approach:

I added an event to SearchDialog that would fire whenever the search pattern DP changed:

public string Search
{
    get { return (string)GetValue(SearchProperty); }
    set { SetValue(SearchProperty, value); }
}

public static readonly DependencyProperty SearchProperty =
    DependencyProperty.Register("Search", typeof(string), typeof(SearchDialog),
    new PropertyMetadata(null, new PropertyChangedCallback(OnSearchChanged)));

private static void OnSearchChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    // call to instance method
    ((SearchDialog)d).OnSearchChanged(e);
}

protected virtual void OnSearchChanged(DependencyPropertyChangedEventArgs e)
{
    if (SearchChanged != null)
     this.SearchChanged(this, e);
}

public event DependencyPropertyChangedEventHandler SearchChanged;

After this I just added another DP in the DataNavigator:

public string Search
{
    get { return (string)GetValue(SearchProperty); }
    set { SetValue(SearchProperty, value); }
}

public static readonly Windows.DependencyProperty SearchProperty =
Windows.DependencyProperty.Register("Search", typeof(string), typeof(DataNavigator),
new Windows.PropertyMetadata(null));

And then hooked up the Navigator's DP to the SearchDialog's DP so that changes to the Search property would be propagated through to the DataNavigator which is then bound to the V & VM.

// Inside the Loaded Event:
this._searchDialog.SearchChanged +=
    new System.Windows.DependencyPropertyChangedEventHandler(Search_Changed);

// Handler:
private void Search_Changed(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
    string search = this._searchDialog.GetValue(SearchDialog.SearchProperty) as string;
    this.Search = search != null ? search.ToString() : null;
}

The rest of things remain the same as above and I'm getting the effect I was looking for.

Nick Gotch