1

I got a Windows Runtime component authored in C++/CX that contains four dependency properties. Three of those properties set the color channels red, green and blue in the underlying renderer. The C++/C code for one such property looks as follows:

uint8_t DemoControl::Red::get()
{
  return static_cast<uint8_t>(GetValue(RedProperty));
}

void DemoControl::Red::set(uint8_t r)
{
  SetValue(RedProperty, r);
}

DependencyProperty^ DemoControl::_redProperty =
  DependencyProperty::Register("Red",
                               uint_t::typeid,
                               DemoControl::typeid,
                               ref new PropertyMetadata(127, ref new PropertyChangedCallback(&DemoControl::OnRedChanged)));

void DemoControl::OnRedChanged(DependencyObject^ d, DependencyPropertyChangedEventArgs^ e)
{
  DemoControl^ DemoControl = static_cast<DemoControl^>(d);
  DemoControl->renderer->SetRed(static_cast<uint8_t>(e->NewValue));
}

The fourth property returns the entire color, i.e. it is a combination of the values of the three other properties.

The question is, how would I update that color property if either the red, green or blue property changes without triggering the code attached to the color property via data binding?

A similar question has been asked here but for WPF. The answer suggests to use value coercion but this seems to be a feature unavailable to Windows Runtime components. The PropertyMetadata object used when registering the dependency property does not support CoerceValueCallback from what I can see.

ackh
  • 1,648
  • 2
  • 18
  • 36

1 Answers1

0

I'm not a C++ expert, but at least for your scenario, I think I can help.

You can register the same callback for multiple Dependency Properties. So in your specific case, you could just have a single OnColorComponentChanged callback:

void DemoControl::OnColorComponentChanged(DependencyObject^ d, DependencyPropertyChangedEventArgs^ e)
{
  DemoControl^ DemoControl = static_cast<DemoControl^>(d);

  if (e->Property == DemoControl::RedProperty) // Hand Wave Syntax Here
  {
    DemoControl->renderer->SetRed(static_cast<uint8_t>(e->NewValue));
  }
  else if (e->Property == DemoControl::GreenProperty)
  {
    DemoControl->renderer->SetGreen(static_cast<uint8_t>(e->NewValue));  
  }
  else if (e->Property == DemoControl::BlueProperty)
  {
    DemoControl->renderer->SetBlue(static_cast<uint8_t>(e->NewValue));  
  }

  // Hand Wave Here
  DemoControl->Color = MakeColor(DemoControl->Red, DemoControl->Green, DemoControl->Blue);
}
Michael Hawker - MSFT
  • 1,572
  • 12
  • 18
  • Thanks for your input, really appreciated. Your approach works well for the three properties that represent the individual color channels, i.e. they could share the same callback. However, the callback of the combined color property needs to update the individual color channel properties. To prevent an infinite loop where they perpetually update each other, I split the callbacks and use booleans to prevent consecutive callbacks from being called. I leave the question open for a bit. Maybe someone comes up with a Windows Runtime mechanism that I'm unaware of. If not I'm posting my solution. – ackh May 19 '20 at 13:09
  • Yeah, for the reverse the guard boolean makes sense. While it won't help you directly, please feel free to file a suggestion on the [Windows Community Toolkit](https://aka.ms/wct). I think it'd be great if we could brainstorm some helpers or something in the future for these types of scenarios. – Michael Hawker - MSFT May 24 '20 at 04:05