Создание статического синглтона / хранилища для настроек с привязкой INotify для WPF

Моя цель - создать синглет с общими данными, настройками и т. Д. Моего приложения. Я хочу, чтобы он был синглетоном для всего моего приложения, и чтобы он имел возможность двустороннего связывания в WPF с использованием INotify.

Я читал, что .net 4.5 может использовать StaticPropertyChanged, поэтому мне интересно, как я бы реализовал это ниже, поскольку документация для этого кажется пятнистой.

public static class Global
{
    public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;
    private static void CallPropChanged(string Prop)
    {
        StaticPropertyChanged?.Invoke(Settings, new PropertyChangedEventArgs(Prop));
    }
    private static Store Settings = new Store();

    public static int setting1
    {
        get { return Settings._setting1; }
        set { if (value != Settings._setting1) { Settings._setting1 = value; CallPropChanged("setting1"); } }
    }
}

internal sealed class Store
{
    internal int _setting1;
}

На правильном ли я пути к тому, чего хочу достичь?

Изменить: внесены некоторые изменения:

public sealed class Global:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    static readonly Global _instance = new Global();

    private int _setting1;
    private int _setting2;

    private void CallPropChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        CallPropChanged(propertyName);
        return true;
    }

    private Global() { }

    public static int setting1
    {
        get { return _instance._setting1; }
        set { _instance.SetField(ref _instance._setting1, value); }
    }
    public static int setting2
    {
        get { return _instance._setting2; }
        set { _instance.SetField(ref _instance._setting2, value); }
    }

}

person Wobbles    schedule 04.10.2016    source источник
comment
Сработало ли то, что вы пробовали? Если да, то какой у вас вопрос? Если нет, что произошло и в чем конкретно вам нужна помощь? Мне кажется, что если вы реализуете синглтон (размещенный вами код не делает этого), то сам синглтон-объект может просто реализовать INotifyPropertyChanged как обычно. Уточните вопрос, чтобы было понятно, с чем на самом деле у вас проблемы. Убедитесь, что вы включили хороший минимально воспроизводимый пример, который надежно воспроизводит любую проблему, с которой вы столкнулись.   -  person Peter Duniho    schedule 04.10.2016
comment
@PeterDuniho Не является ли определение хранилища экземпляров внутри статического одним из способов создания синглтона? Или он все равно создает новый экземпляр магазина от каждого звонка? Я хочу привязаться к статике, а статика не может реализовать INotify   -  person Wobbles    schedule 04.10.2016
comment
Не является ли определение хранилища экземпляров внутри статического одним из способов создания синглтона? - нет. Термин синглтон имеет очень конкретное значение и не применяется к опубликованному вами коду. С синглтоном у вас будет свойство public static, которое возвращает single экземпляр вашего класса, но сам класс и все его члены по-прежнему нестатичны. Затем вы можете реализовать интерфейсы (например, INPC). Вы можете вместо использовать StaticPropertyChanged, но это не синглтон. Это просто статический класс, с которым может справиться WPF. См., Например, этот ответ для получения дополнительной информации.   -  person Peter Duniho    schedule 04.10.2016
comment
@PeterDuniho Есть ли польза от Singleton-подхода? Могу ли я выполнить привязку к синглтону во время разработки?   -  person Wobbles    schedule 04.10.2016
comment
Имеет ли одноэлементный подход какие-либо преимущества? - с помощью синглтона вы можете реализовать любой интерфейс, который вам нужен / нужен. Это невозможно со статическими классами в C #. Могу ли я выполнить привязку к синглтону во время разработки? - я не знаю, почему вы не можете этого сделать. Ты пробовал? Были ли у вас при этом какие-то особые проблемы? Если вы можете выполнить привязку к статическому свойству (что вы можете), естественно, вы можете привязаться к экземпляру класса, возвращаемому статическим свойством.   -  person Peter Duniho    schedule 04.10.2016
comment
@PeterDuniho: Ну, сейчас это вроде просто академическое, хочу убедиться, что у меня правильный подход, прежде чем я буду строить на нем слишком много. Я добавил еще один образец кода, он больше похож на синглтон? вы видите какие-либо проблемы с этим подходом?   -  person Wobbles    schedule 05.10.2016
comment
Код все еще не синглтон. Также обновленный код не будет работать для привязки, потому что, хотя событие PropertyChanged является общедоступным, нет общедоступного экземпляра объекта, к которому можно было бы привязаться. Я не понимаю, какова ваша фиксация на вопросе синглтона; Если для ваших нужд достаточно общедоступных статических свойств, почему шаблон singleton вообще обсуждается? Итог: я до сих пор не совсем понимаю, о чем вы здесь спрашиваете. Академический не по теме, поскольку он, как правило, в основном основан на мнении. Хороший вопрос для Stack Overflow связан с конкретной проблемой, которую нужно решить.   -  person Peter Duniho    schedule 05.10.2016
comment
@PeterDuniho Как это не синглтон, он реализует шаблон синглтона из MSDN, и привязка, похоже, работает нормально   -  person Wobbles    schedule 05.10.2016
comment
Привязка не имеет никакого отношения к тому, является ли это синглтоном. И я уверен, что о какой бы странице MSDN вы ни говорили, неверно, что она реализует шаблон singleton из MSDN. Либо страница, на которую вы ссылаетесь, на самом деле не показывает реализацию одноэлементного шаблона, либо вы на самом деле не следовали примеру на странице. Я предполагаю, что есть небольшая вероятность, что MSDN имеет неправильное описание шаблона singleton, но мне это кажется маловероятным. См. en.wikipedia.org/wiki/Singleton_pattern.   -  person Peter Duniho    schedule 05.10.2016
comment
Что касается привязки, то в опубликованном вами коде нет события PropertyChanged, на которое WPF может подписаться, поэтому, хотя вы можете обнаружить, что привязка работает, когда свойства установлены до создания привязки, она не будет динамической. Т.е. изменения свойств не будут отражены в цели привязки.   -  person Peter Duniho    schedule 05.10.2016
comment
@PeterDuniho Что? Да, безусловно, он реализует INotify и имеет событие PropertyChanged, вы смотрите на код, который я добавил выше, или на что-то еще?   -  person Wobbles    schedule 06.10.2016
comment
он реализует INotify и имеет событие PropertyChanged - да, это так. Но WPF не может получить объект, реализующий интерфейс, и поэтому не может подписаться на событие.   -  person Peter Duniho    schedule 06.10.2016
comment
@PeterDuniho Тогда почему это работает?   -  person Wobbles    schedule 06.10.2016
comment
Я сомневаюсь, что это так. Первоначально связанное значение будет в порядке, но если вы когда-нибудь измените значение свойства, показанный вами код не сможет уведомить WPF об изменении свойства. Если отображаемое значение действительно обновляется, значит, у вас есть что-то еще, что вызывает это. Это не меняет того факта, что опубликованный вами код не реализует одноэлементный шаблон и не предоставляет средств для уведомлений об изменении свойств в WPF. Если вам нужна более конкретная информация, вам нужно предоставить хороший минимально воспроизводимый пример. Я могу прокомментировать только тот небольшой фрагмент кода, которым вы уже поделились.   -  person Peter Duniho    schedule 06.10.2016
comment
@PeterDuniho Вы все время говорите, что он не работает, но он работает, уже пробовал, и он реализует как singleton patter, так и INotify, я думаю, вы, должно быть, смотрите не на тот код ...   -  person Wobbles    schedule 06.10.2016
comment
Во-первых, нет никаких сомнений в том, что опубликованный вами код не реализует одноэлементный шаблон. Это очевидный факт. Если вы думаете иначе, вы просто не понимаете, что такое шаблон singleton. Что касается уведомления об изменении свойства. Докажите это. Опубликуйте хороший минимально воспроизводимый пример, в котором используется точно код, который вы разместили выше, и не более того, в качестве источника данных для сценария привязки данных XAML, где вы можете изменить значение свойства, и целевое свойство будет обновлено для соответствия. То, что ваш класс реализовал интерфейс, не означает, что он работает.   -  person Peter Duniho    schedule 06.10.2016


Ответы (1)


Я не знаком со StaticPropertyChanged, но я реализовал одноэлементные модели просмотра следующим образом:

public class MyViewModel : ViewModelBase 
{
    public static MyViewModel Instance { get; set; }
    public static ICommand MyCommand { get; set; }

    public MyViewModel()
    {
        Instance = this;
    }
}

и связанные кнопки и т. д. в XAML следующим образом:

<Button Content="Click Me" Command="{x:Static vm:MyViewModel.MyCommand}" CommandParameter="MyParameters" />

Вы можете использовать префикс x: Static для привязки к статическим полям, и вы можете использовать INotifyPropertyChanged в обычном режиме ... Вы можете заметить, что эта конкретная привязка на самом деле не требует одноэлементного экземпляра виртуальной машины, а придерживается одноэлементной модели , вы также можете выполнить привязку к {x: Static vm: MyViewModel.Instance.Whatever}

person Dave Smash    schedule 04.10.2016
comment
Я предполагаю, что вам нужно получить доступ к свойствам через Instance, а в чем смысл статического свойства внутри экземпляра? MyCommand должен быть экземпляром? Единственная причина сделать MyCommand статическим, если это был ярлык для доступа к MyViewModel.Instance._MyCommand полю? Верно? Или я просто потерял лол. - person Wobbles; 05.10.2016
comment
Вышеупомянутая реализация также не является одноэлементной. Шаблон singleton имеет некоторые особые требования, одно из которых состоит в том, что невозможно создать более одного экземпляра типа. Конструктор является частным, и есть статическое поле, в котором хранится единственный экземпляр этого типа и которое инициализируется только один раз. Лучшая реализация шаблона также не будет инициализировать поле в конструкторе. В .NET класс Lazy<T> полезен для синглтонов, создание которых требует больших затрат и которые не всегда используются, в противном случае достаточно простого инициализатора поля. - person Peter Duniho; 05.10.2016
comment
@PeterDuniho В моем втором примере вы говорите, что это тоже не синглтон. Я копирую свой код из примеров синглтонов, поэтому я не уверен, что еще есть. - person Wobbles; 05.10.2016
comment
В моем втором примере это - что? Частью шаблона синглтона является то, что единственный экземпляр может использоваться вне класса синглтона. В вашем втором примере этого точно нет. Экземпляр Global является частным для класса; там нет ничего, что позволило бы любому другому коду получить к нему доступ. - person Peter Duniho; 05.10.2016
comment
@PeterDuniho О чем вы говорите, статические свойства являются общедоступными и раскрывают экземпляр ... Я не думаю, что вы смотрите на правильный код. - person Wobbles; 06.10.2016
comment
@Wobbles: статические свойства общедоступны - да, это так. и выставить экземпляр - нет, они этого не делают. Они возвращают значения из экземпляра, но сам экземпляр остается инкапсулированным и частным для класса. - person Peter Duniho; 06.10.2016
comment
@PeterDuniho, поэтому мне не нужно открывать экземпляр, потому что меня это не волнует, только поля внутри него. - person Wobbles; 06.10.2016
comment
@Wobbles: Мне не нужно открывать экземпляр, потому что он меня не волнует - я не могу сказать. Вы просто не предоставили достаточно подробностей. По крайней мере, если вы хотите получать уведомления об изменении свойств, вам нужно реализовать это где-нибудь. Без раскрытия экземпляра он, очевидно, не будет предоставлять этого, поскольку WPF не сможет подписаться на событие PropertyChanged. Если хотите, вы можете реализовать всех публичных членов как static и включить StaticPropertyChanged. Но вам все равно нужно вызывать это событие при изменении свойства каким-то образом. - person Peter Duniho; 06.10.2016