简体   繁体   中英

Binding visibility to static property

I have a control that has a label on it, that I would like to hide or show based on a global menu item for all instances of my control. If I click the button to hide labels, I want to to hide all of them.

My xaml looks like this:

<TextBlock Name="_label" Visibility="{Binding LabelShown}" VerticalAlignment="Center" HorizontalAlignment="Center"/>

in my code behind I have a property:

    private static Visibility _labelShown;
    public static Visibility LabelShown
    {
        get { return _labelShown; }
        set { _labelShown = value; }
    }

And I set DataContext = this;

When I change the static property, nothing happens. I assume this is because no controls are getting a property changed notification. I cannot implement INotifyPropertyChanged on it, because I cannot reference the non static property changed handler from my static property.

I feel like maybe this isn't the best way to do this, but I would really like to have one button (many levels above my actual control) drive the visibility for all instances.

CodeNaked's solution works, but it uses a Singleton which has downsides when doing unit-testing. I prefer to approach global access problems by just having one settings instance at the application root, ie the App -class.

eg

public partial class App : Application
{
    private static Settings _settings = new Settings();
    public static Settings Settings
    {
        get { return _settings; }
    }

        ...

Where this property contains all the settings for the application. Binding then looks like this:

"{Binding Source={x:Static local:App.Settings}, Path=LabelsShown}"

Edit: If you are worried about dependencies you could also inject a reference to those settings in the constructor of any class where you need it, using its minimal interface.

eg

public class MyControl : ContentControl
{
    public interface IMyControlSettings
    {
        public bool LabelsShown { get; set; }
    }

    private IMyControlSettings _settings;

    public MyControl(IMyControlSettings settings)
    {
        _settings = settings;
        DataContext = _settings; // For easy binding, in most cases you probably do not want to do that since it prevents DataContext inheritance.
    }
}
public class Settings : Test.MyControl.IMyControlSettings, INotifyPropertyChanged
{
    public bool LabelsShown { get; set; }
    ...
}

You can do something like this:

public class MySettings : INotifyPropertyChanged {
    private MySettings() {
    }

    private Visibility _labelShown;
    public Visibility LabelShown
    {
        get { return _labelShown; }
        set {
            _labelShown = value;
            // Raise PropertyChanged event for LabelShown
        }
    }

    private static MySettings _instance;
    public static MySettings Instance
    {
        get {
            if (_instance == null)
                _instance = new MySettings();
            return _instance;
        }
    }
}

Then bind to it like {Binding Path=LabelShown, Source={x:Static local:MySettings.Instance}}

The only thing you need to add is the local xmlns which would be like xmlns:local="clr-namespace:MyNamespace"

I found a kinda lame workaround:

    public static Visibility LabelShown
    {
        get { return _labelShown; }
        set
        {
            _labelShown = value;
            if ( StaticEvent != null )
            {
                StaticEvent();
            }
        }
    }

    private static event Action StaticEvent;

    public event PropertyChangedEventHandler PropertyChanged
    {
        add { StaticEvent += () => value(this, new PropertyChangedEventArgs("LabelShown")); }
        remove { StaticEvent -= () => value(this, new PropertyChangedEventArgs("LabelShown")); }
    }

It works, but I am a little worried about the remove handler actually being able to remove the anonymous method like that. Would that cause memory problems if many controls are disposed?

I tend to prefer CodeNaked's solution, but I wanted to offer this for discussion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM