Beebok
Beebok

Reputation: 395

How does a XAML attribute bind to a INotifyPropertyChanged object

have a class that implements the INotifyPropertyChanged interface like this:

public class ColorNotify : INotifyPropertyChanged
{   
    public event PropertyChangedEventHandler PropertyChanged;

    private SolidColorBrush bindableColor;
    public SolidColorBrush BindableColor
    {
        get { return bindableColor; }
        set
        {
            bindableColor = value;
            OnPropertyChanged("BindableColor");
        }
    }  

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));   
        } 
    } 
}

One of the fields in my MainPage.xaml.cs there is this:

private ColorNotify DisabledColor; 

But I've also tried the above field as a property instead like this:

private ColorNotify disabledColor;
public ColorNotify DisabledColor
{
    get
    { return disabledColor; }
    set
    { disabledColor = value; }
}

Also in MainPage.xaml.cs is this method:

private void Legend_Refreshed(object sender, Legend.RefreshedEventArgs Lgd_Refreshed_EvArgs)
{
    LayerItemViewModel layerItmViewMdl;
    ObservableCollection<LayerItemViewModel> layerItms;

    layerItmViewMdl = Lgd_Refreshed_EvArgs.LayerItem;
    Layer legendItemLyr = layerItmViewMdl.Layer; 

    if (!legendItemLyr.IsInitialized)
    { 
        DisabledColor = new ColorNotify();
        DisabledColor.BindableColor = new SolidColorBrush(Colors.Red);
    }
    ...
    ...
}

In the MainPage.xaml I have this:

<esri:Legend 
        Map="{Binding ElementName=theMap}"
        LayerIDs="..." 
        Refreshed="Legend_Refreshed">
               <esri:Legend.MapLayerTemplate>
                       <DataTemplate>
                              <StackPanel Orientation="Horizontal" Width="Auto">
                                        <CheckBox Content="{Binding Label}" 
                                            Width="Auto" 
                                            IsChecked="{Binding IsEnabled, Mode=TwoWay}"
                                IsEnabled="{Binding IsInScaleRange}" 
                                            Foreground="{Binding Source=DisabledColor, Path=BindableColor}">
                                        </CheckBox>
                                        <Slider Maximum="1"  
                                            Value="{Binding Layer.Opacity, Mode=TwoWay}" 
                                            Width="80" />
                              </StackPanel>
                       </DataTemplate>
...
...
...
</esri:Legend>

Notice the XAML code above:

Foreground="{Binding Source=DisabledColor, Path=BindableColor}">

That didn't work.

I then tried this in the XAML:

Foreground="{Binding BindableColor}"

But that didn't work either How do I bind the Foreground to the BindableColor property of the ColorNotify class? What should the XAML binding look like when binding to a INotifyPropertyChanged object? (Not through MVVM)

Upvotes: 1

Views: 941

Answers (2)

Tim S.
Tim S.

Reputation: 56536

Edit: Based on the below comment discussion, I think you should create an IValueConverter with a Convert method like this:

return new SolidColorBrush((bool)value ? Colors.Black : Colors.Red);

Let's say your IValueConverter class is named InitializedColorConverter, in a namespace you've added as xmlns local. Use it like this in the XAML:

<UserControl.Resources>
    <local:InitializedColorConverter x:Key="InitializedColorConverter" />
</UserControl.Resources>
...
Foreground="{Binding IsInitialized, Converter = {StaticResource InitializedColorConverter}}"

End Edit. I'll leave the rest here as it may be useful for people with similar problems:

You'll need to change the field on MainPage to a public property:

public ColorNotify DisabledColor { get; private set; }

If you want the binding to update when DisabledColor itself is changed, implement INotifyPropertyChanged on MainPage (and this property) as well.

One of the simpler ways to get the correct value bound is to do it programmatically. To do so, put a Loaded handler on your object:

<CheckBox Content="{Binding Label}" 
          Width="Auto" 
          IsChecked="{Binding IsEnabled, Mode=TwoWay}"
          IsEnabled="{Binding IsInScaleRange}" 
          Loaded="MyCheckBoxLoaded">

And have your handler do something like this:

private void MyCheckBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
{
    var cb = (CheckBox)sender;
    cb.SetBinding(Control.ForegroundProperty,
new System.Windows.Data.Binding("DisabledColor.Bindablecolor") { Source = this });
}

The reason it may seem convoluted is that the Source needs to be your MainPage, and unfortunately in Silverlight, that's not as easy as it seems it ought to be.

If your DisabledColor will never change during the life of the page, you could keep it a private field (mark it readonly to ensure this is true) and do this instead in the handler:

cb.SetBinding(Control.ForegroundProperty,
new System.Windows.Data.Binding("Bindablecolor") { Source = this.DisabledColor });

Upvotes: 1

Shoaib Shaikh
Shoaib Shaikh

Reputation: 4585

If you change/init

private ColorNotify DisabledColor; 

after View/ViewModel load then you would need to change this property to public and implement INotifyPropertyChange on it as well same as you have done on ColorNotify.

Upvotes: 0

Related Questions