Coerced Value of a Dependency Property not propagated to target or source

Viewed 160

Problem:

I have a custom Dependency Property (DP) called SelectedStoreString in a custom control called StorePicker. The DP has a PropertyChangedCallback and a CoerceValueCallback. The DP is two-way bound to a property in the view model by the same name. When the source is assigned a value in the view model, the CoerceValueCallback gets called, and it returns the final value that should be propagated between the target DP and the source in the view model (it could be the same as the value assigned or different if it got changed in the handler).

The value is then sent to the PropertyChangedCallback. The problem is the coerced value returned from the CoerceValueCallback never propagates to the target or the source. I'm using the DevExpress WPF Framework's POCOViewModels, so the INotifyPropertyChanged interface is implemented in the background.

Code:

//--------------------Poco view model--------------------------------------------------
  [POCOViewModel]
  public class FindOrdersViewModel
  {

    public virtual string SelectedStoreString { get; set; }


    public FindOrdersViewModel()
    {      
      SelectedStoreString = "48,49,55";
    }


    public static FindOrdersViewModel Create()
    {
      return ViewModelSource.Create(() => new FindOrdersViewModel());
    }

  }

//--------------------Dependency Property and its Handlers-----------------------------
    public static DependencyProperty SelectedStoreStringProperty = DependencyProperty.Register(nameof(SelectedStoreString), typeof(string), typeof(StorePicker), new FrameworkPropertyMetadata("",
                                                                                                                                                                                               FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                                                                                                                                                                                               new PropertyChangedCallback(OnSelectedStoreStringChanged),
                                                                                                                                                                                               new CoerceValueCallback(CoerceSelectedStoreString),
                                                                                                                                                                                               false,
                                                                                                                                                                                               UpdateSourceTrigger.PropertyChanged));

    public string SelectedStoreString
    {
      get
      {
        return (string) GetValue(SelectedStoreStringProperty); // _selectedStoreString;
      }

      set
      {
        SetValue(SelectedStoreStringProperty, value);
      }
    }


    private static void OnSelectedStoreStringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

      StorePicker storePicker = d as StorePicker;

      if (d != null)
      {
        Dictionary<int, Store> sDct = new Dictionary<int, Store>();
        foreach (Store store in _stores)
          sDct.Add(store.STORE, store);
        string value = e.NewValue as string;

        if (value != null && value != "")
        {
          string[] strs = value.Split(',');
          foreach (string s in strs)
          {
            try
            {
              int x = Convert.ToInt32(s);
              Store outStore = sDct[x];
              if (outStore != null)
              {

                if (!outStore.InActive)
                {
                  storePicker.listBoxEdit1.SelectedItems.Add(outStore);

                }


              }
            }
            catch
            {
            }
          }
        }
      }
    }

    private static object CoerceSelectedStoreString(DependencyObject d, object v)
    {
      StorePicker storePicker = d as StorePicker;

      string finalSelectedStoresString = ""; //because the selectedstorestring may contain an Inactive store code we may need to adjust the string that was assigned
      if (d != null)
      {
        string[] storeCodes = ((string)v) == "" ? new string[0]: ((string)v).Split(',');
        foreach (string s in storeCodes) 
        {
          Store temp = _stores.Find(x => x.STORE == Convert.ToInt32(s) && !x.InActive);
          if (temp != null) 
          {
            finalSelectedStoresString += temp.STORE + ","; 
          }
        }

        if (finalSelectedStoresString != "")
        {
          finalSelectedStoresString = finalSelectedStoresString.Remove(finalSelectedStoresString.Length - 1, 1); //remove the ending comma from the string if it has one
        }

      }

      return finalSelectedStoresString;
    }

//------------------------------How the control is used in xml---------------------------------------
<ctl:StorePicker x:Name="StorePicker" Grid.Row="2" Grid.Column="1" Margin="10,-4,0,4" StoreType="All"  SelectedStoreString="{Binding SelectedStoreString,Mode=TwoWay}" IsAllStoresSelected="{Binding IsAllStoresSelected, Mode=TwoWay}"/>

What I've tried:

  • Calling storePicker.SetCurrentValue (SelectedStoreStringProperty, e.NewValue as string) from the PropertyChangedCallback. This either resulted in an infinite loop of callbacks or absolutely nothing if I used a Boolean state variable to prevent the infinite loop. But nonetheless, did not update the binding.

  • Setting the binding mode to Explicit and calling storePicker.GetBindingExpression(SelectedStoreStringProperty).UpdateSource() and storePicker.GetBindingExpression(SelectedStoreStringProperty).UpdateTarget() to manually update the bindings. Still did not update the target or source.

  • Setting the DP using these following methods (all of which just destroyed the binding, thus defeating the purpose): storePicker.SetValue(SelectedStoreStringProperty, e.NewValue as string), SelectedStoreString = e.NewValue as string

What I need:

I need the ability to change Dependency Property values in the code-behind of a custom control and have those values be propagated to the target DP and the source property in the view model.

0 Answers
Related