Значение свойства Singleton неверно при вызове из другого потока - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть следующий шаблон Singleton для ViewModel моих опций:

    private static volatile GeneralOptionsViewModel instance;
    private static object syncRoot = new object();
    /// <summary>
    /// threadsave singleton
    /// </summary>
    public static GeneralOptionsViewModel Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new GeneralOptionsViewModel();
                }
            }

            return instance;
        }
    }

В моем XAML у меня есть палитра цветов из расширенного пакета инструментов:

<xctk:PropertyGridEditorColorPicker Background="Transparent" Name="face" 
Margin="5,0" Width="50" BorderBrush="#32FFFFFF" BorderThickness="1" 
SelectedColor="{Binding FaceRectColor, Mode=OneWayToSource, 
UpdateSourceTrigger=PropertyChanged}"/>

Как вы можете видеть, оно связано со FaceRectColor свойством класса GeneralOptionsViewModel, которое определено следующим образом. В сеттере происходит преобразование в MCvScalar (также свойство того же класса), формат, который мне позже понадобится для моего приложения:

    public Color FaceRectColor
    {
        get
        {
            return faceRectColor;
        }
        set
        {
            if (faceRectColor != value)
            {
                faceRectColor = value;
                FaceRectColorScalar = new MCvScalar(value.B, value.R, value.G, value.A);
                SetProperty(ref faceRectColor, value);
            }
        }
    }

Моя проблема сейчас заключается в том, что привязка работает, и правильные значения записываются в переменную, однако, когда я вызываю синглтон со свойством из другого класса - и из другого потока - он всегда показывает ноль для всех цветов каналы. Однако, если я нарушу программу непосредственно в классе синглтона, я смогу увидеть правильные значения. AFAIK, синглтон должен быть потокобезопасным, поэтому я ищу причину такого поведения. Я предполагаю, что есть проблема с многопоточностью, так как другие свойства класса singleton отображаются правильно, но они вызываются только в основном потоке.

Edit: в моем случае все значения свойств класса singleton устанавливаются до того, как рабочий поток активен. Это означает, что никаких изменений в течение рабочего потока не происходит.

Редактировать II: Вот полный проект для оценки кода. В классе CameraViewModel в строке 202 находится соответствующий вызов функции, где я хочу передать значения из синглтона.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Ваш "синглтон" содержит открытый конструктор, который фактически делает его не синглтоном. И вы не привязаны к синглтону в вашем GeneralOptionsView.

Если вы действительно хотите, чтобы GeneralOptionsViewModel был синглтоном, вы должны реализовать его следующим образом:

public sealed class GeneralOptionsViewModel : ViewModelBase
{
    private static readonly GeneralOptionsViewModel _instance = new GeneralOptionsViewModel();
    private GeneralOptionsViewModel()
    {
        GetAvailableCameraList();
        DetectorTypeList = new List<string>() { "Cascade Detector" };
        SelectedDetectorTypeIndex = 0;
    }

    public static GeneralOptionsViewModel Instance => _instance;

    //...
}

Затем вы должны установить DataContext вашего вида в синглтон:

<Grid DataContext="{Binding Source={x:Static local:GeneralOptionsViewModel.Instance}}">
0 голосов
/ 01 ноября 2018

Когда ваше свойство изменяется и происходит в другом потоке, в вызывающем потоке выполняются вызовы, которые делаются для уведомления всех (в частности, пользовательского интерфейса) об этом изменении. Доступ к пользовательскому интерфейсу в потоке, который не является потоком пользовательского интерфейса, является плохой идеей. Это может иногда работать. Но это рано или поздно провалится.

Решением вашей текущей проблемы является изменение свойства в потоке пользовательского интерфейса.

Тем не менее, возможно, вам следует подумать о том, нужен ли вам Синглтон. Это огромный красный признак того, что что-то не так со структурой вашей программы. Вам не нужно нужен синглтон. Ничего плохого не произошло бы, если бы в каком-то другом контексте была вторая модель настроек. Вы, кажется, хотите Singleton, потому что так легко и просто иметь глобальную переменную. Это недостаток синглтона. Это недостаток , в который вы покупаете, потому что вам нужно что-то из этого паттерна. Если вы обнаружите, что используете этот шаблон только потому, что недостаток дает вам оправдание для использования глобальной переменной, вы делаете шаблоны неправильно. Это анти-паттерн .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...