1
votes

I'm trying to do a simple OneWay binding for a user control, but I honestly don't understand why some parts aren't working. To be simple, I created a WPF standard UserControl with some dependency properties. In my main window, I hide/display the UserControl depending of some events, and I bound the properties to my main window viewmodel data. However, doing that makes NOT my UserControl refreshing for SOME parts. For exampl, I have a SearchString dependency property on my UserControl :

public static readonly DependencyProperty SearchStringProperty = DependencyProperty.Register("SearchString",
           typeof(string), typeof(DisplayMailView), new UIPropertyMetadata(null));

public string SearchString
    {
        get { return (string)GetValue(SearchStringProperty); }
        set
        {
            SetValue(SearchStringProperty, value);
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("SearchString"));
            }
            var loFinds = richEditControl1.Document.FindAll(SearchString, SearchOptions.WholeWord);

            foreach (var find in loFinds)
            {
                var oDoc = find.BeginUpdateDocument();
                var oChars = oDoc.BeginUpdateCharacters(find);
                oChars.BackColor = System.Drawing.Color.Yellow;
                oDoc.EndUpdateCharacters(oChars);
                find.EndUpdateDocument(oDoc);
            }
        }
    }

This one in UserControl is bound to the SearchString member of my main Window viewmodel

<local:DisplayMailView SearchString="{Binding DataContext.SearchString, RelativeSource={RelativeSource AncestorType={x:Type Window}}, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True,NotifyOnTargetUpdated=True,Mode=TwoWay}"/>

On my ViewModel :

 public string SearchString
    {
        get
        {
            return _searchString;
        }
        set
        {
            _searchString = value;
            if (!string.IsNullOrWhiteSpace(value))
                DataGridService.FocusFirstRow();
            RaisePropertyChanged();
        }
    }

I put a break point into the set of my SearchString in my main window viewmodel, the value is set. However, when I put a breakpoint into the set of my SearchString on the UserControl, it never fire ?

Also, the dataContext of my UserControl is set :

    (this.Content as FrameworkElement).DataContext = this;

I precise that my UserControl constructor is only called one time at launch, the other things must be dynamically refresh depending on user actions.

Does someone have an idea ? I have no errors in output window Thanks

1

1 Answers

6
votes

This is a common misconception. When a DependencyProperty's value changes, the code in its CLR property's set is not executed. You need to use a PropertyChanged callback if you want to execute some code whenever the property value changes.

Your UserControl code should look like this, instead:

public static readonly DependencyProperty SearchStringProperty =
    DependencyProperty.Register(
        "SearchString",
        typeof(string),
        typeof(DisplayMailView),
        new UIPropertyMetadata(null, OnSearchStringChanged));
        // This sets OnSearchStringChanged as the PropertyChanged callback

public string SearchString
{
    get { return (string)GetValue(SearchStringProperty); }
    set
    {
        SetValue(SearchStringProperty, value);
        //  Any code you put here won't be executed 
        // when the DependencyProperty value changes
    }
}

private static void OnSearchStringChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    //  This part is not needed, DependencyProperties already
    // notify of their changes automatically
    //if (PropertyChanged != null)
    //{
    //    PropertyChanged(this, new PropertyChangedEventArgs("SearchString"));
    //}

    var control = sender as DisplayMailView;     

    var loFinds = control.richEditControl1.Document.FindAll(SearchString, SearchOptions.WholeWord);

     foreach (var find in loFinds)
     {
         var oDoc = find.BeginUpdateDocument();
         var oChars = oDoc.BeginUpdateCharacters(find);
         oChars.BackColor = System.Drawing.Color.Yellow;
         oDoc.EndUpdateCharacters(oChars);
         find.EndUpdateDocument(oDoc);
     }
}