1

Closed

Bound controls works odd when using UpdateControls for WPF

description

Hi

Last fix for PropertyGrid works very well. Thank you very much. I got another issue with UpdateControl for WPF.

First, this is my scenario:

Domain Model

class PersonModel
{
 private Independent<string> address=new Independent<string>();
 public string Address
    {
        get
        {
            return address;
        }
        set
        {
            address.Value = value;
        }
    }
}

ViewModel
class PersonVM
{
 PersonModel model;
 public PersonVM(PersonModel model)
 {
   this.model=model;
    }

  public string Address
{
get
{
return model.Address;
}
set
{
this.model.Address=value;
}

public bool HasAddress
{
get;set;
}
}

MainWindow

public MainWindow()
    {
        InitializeComponent();
        var contextData= ForView.Wrap(new PersonVM(new PersonModel);
        propertyGrid.DataContext = contextData;
        checkBox.DataContext = contextData;
    }
MainWindow xaml
<CheckBox IsChecked="{Binding HasAddress}" Name="checkBox"></CheckBox>


So, PropertyGrid works very well for showing Address. However, CheckBox works odd. If it is unchecked, when you click it, CheckBox always automatically goes back to unchecked, which means you can not change CheckBox's state, while showing Address works very well.

The only difference is that Address in ViewModel contains Indenpendent property, while HasAddress does not have. Should I alway set a independent property to ViewModel's property as underlying property? Is this the design of UpdateControls or it is just bug?
Closed Nov 11, 2013 at 5:48 PM by MichaelLPerry1971
Property needs to be backed by an Independent field.

comments

MichaelLPerry1971 wrote Nov 6, 2013 at 3:26 PM

Without an Independent<bool> or something else backing the HasAddress field, Update Controls can't track dependencies or fire PropertyChanged events. Please try adding an independent and see if that solves the problem.

In general, the view model properties don't need to be one-to-one with independents. For example, HasAddress could be this:
bool HasAddress
{
  get { return !string.IsNullOrEmpty(model.Address); }
  set { if (!value) model.Address = null; }
}
In this example, clearing the check box would null out the address, and entering an address would automatically check the box. Nevertheless, HasAddress is backed by an Independent, so Update Controls can track the dependency and fire PropertyChanged.

chris_wen_11 wrote Nov 6, 2013 at 7:30 PM

Oh. I thought there is a magic that ForView.Wrap can wrap any class to impment INotifyPropertyChanged.

Your solution works perfect and it matches our needs. Thanks.

BTW, From my understanding, ForView.Wrap returns a object for controls to bind. It intercepts those messages of setting and getting properties from controls and fire those PropertyChanged event to refresh controls. Why can not a property of wrapped object without backed Independent fire PropertyChanged. In theory, I think it is possible. Am I right?

I used UpdateControl for winform for some period. I know Winform Control is always checking if its independent property is changed while application is idle. Does WPF do the same thing?

MichaelLPerry1971 wrote Nov 6, 2013 at 8:39 PM

You are correct that ForView.Wrap creates a wrapper object that implements INotifyPropertyChanged. But if there are no Independent fields behind those properties, they will never actually raise the event. Here's why.

The wrapper creates a Dependent for each of the properties. A Dependent tracks the set of Independents that are accessed when the property is updated. When those properties change, the Dependent becomes out-of-date. This causes the wrapper to raise the PropertyChanged event. So if there are no Independents, the event is never fired.

The wrapper does not intercept property sets in order to fire PropertyChanged events. There are other libraries -- like Notify Property Weaver and Postsharp -- that do this. They work based on static analysis of the source code, and can therefore not discover dynamic dependencies, or cross object boundaries. The dependency tracking algorithm, while more work for you, yields more reliable results.

The WPF implementation is doing something very similar to the Windows Forms implementation. But I should clarify that it isn't always checking while the application is idle. That would put unnecessary load on the CPU and hurt battery life, especially in mobile apps. Instead, it's queuing up notifications until the application enters idle time. Then it raises all of the queued notification events. This actually helps performance, because it avoids PropertyChanged event storms.

Thanks for the question. Glad I could help.

chris_wen_11 wrote Nov 11, 2013 at 12:21 PM

That solved me a lot of questions. Thanks!

wrote Nov 11, 2013 at 5:48 PM