Привязываемые элементы управления Singleton при выполнении задач / многопоточности - PullRequest
0 голосов
/ 16 июля 2011

перед публикацией вопроса я провел исследование в течение 10 дней, поэтому очень надеюсь, что кто-нибудь сможет пролить свет на решение этой проблемы.

Проблема в том, что любой привязываемый элемент управления не обновляется после изменения списка привязок из одноэлементного класса. Это распространенная проблема многопоточных приложений. Большинство, если не все решения предлагают предложения, в которых список связывания или коллекция инициализируются из родительского потока, а затем необходимо выполнить некоторый вызов. Не то, что я ищу. Та же проблема сохраняется, если вместо singleton используется статический класс.

По сути, приложение запускает несколько задач, которые, в свою очередь, создают объекты в разных бизнес-классах. Эти объекты отправляют сообщения в список связывания, который должен обновлять список UI, но не обновляет его. И да, объект сообщения находится в списке, а привязка после ЗАДАЧА завершена (элементы показаны). Блокировка / разблокировка доступа к объектам также не является проблемой.

Ценю любые предложения / решения

Урезанная версия бизнес-объектов:

namespace MyNameSpace
{
    public class Message
    {
        private string messageSummary;
        public Message() { }
        public string MessageSummary
        {
            set { messageSummary = value; }
            get { return messageSummary; }
        }
    }
}

Урезанная версия другого класса, выполняющая некоторые операции:

namespace MyNameSpace
{
    public class WorkDoingClass
    {
        public WorkDoingClass() { }
        public void DoSomeWork()
        {
            //some routines
            Message messageObj = new Message();
            messageObj.MessageSummary = "DoSOmrWork Finished";
        }

        public void DoSomeOtherWork()
        {
            //some routines
            Message messageObj = new Message();
            messageObj.MessageSummary = "DoSomeOtherWork Finished";
            AllMessages.Instance.AllMessagesBindingList.Add(messageObj);
        }
    }
}

Singleton:

namespace MyNameSpace
{
    public sealed class AllMessages
    {
        private static readonly AllMessages _instance = new AllMessages();
        private BindingList<Message> _allMessagesBL;

        public WorkDoingClass() { _allMessagesBL = new BindingList<Message>(); }

        public static AllMessages Instance
        {
            get { return _instance; }
        }

        public BindingList<Message> AllMessagesBindingList
        {
            get { return _allMessagesBL};
        }
    }
}

Это также урезанная версия, откуда начинаются звонки:

namespace MyNameSpace
{
    public partial class Form1 : Form
    {
        private Task _TaskSqlData;
        private CancellationTokenSource cTokenSourceSql;

        public Form1()
        {
            InitializeComponent();
            listBox1.DataSource = AllMessages.Instance.AllMessagesBindingList;
            listBox1.DisplayMember = "MessageSummary";
        }

    private void button1_Click(object sender, EventArgs e)
    {
            cTokenSourceSql = new CancellationTokenSource();
            var tokenSqlData = cTokenSourceSql.Token;
            if (this._TaskSqlData != null)
            {
                if (this._TaskSqlData.Status == TaskStatus.Running)
                    this.cTokenSourceSql.Cancel();
                this._TaskSqlData.Dispose();
                this._TaskSqlData = null;
            }
            _TaskSqlData = Task.Factory.StartNew(()
                            => StartDoingWork(this, tokenSqlData, null), tokenSqlData);
    }

    public void StartDoingWork(object sender, CancellationToken ct, EventArgs e)
    {
            if (ct.IsCancellationRequested)
                ct.ThrowIfCancellationRequested();
            WorkDoingClass work = new WorkDoingClass();
            work.DoSomeOtherWork();
    }

1 Ответ

1 голос
/ 16 июля 2011

Ваша проблема в том, что поток (основной поток пользовательского интерфейса), создающий список, отличается от потока (рабочего потока), модифицирующего коллекцию.

Попробуйте следующий код.Это может решить вашу проблему.Я использую SynchronizationContext для синхронизации двух потоков, что выполняет ту же функцию с Control.Invoke () .

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private Task _TaskSqlData;
        private CancellationTokenSource cTokenSourceSql;
        WorkDoingClass _work;

        public Form1()
        {
            InitializeComponent();
            listBox1.DataSource = AllMessages.Instance.AllMessagesBindingList;
            listBox1.DisplayMember = "MessageSummary";
            _work = new WorkDoingClass(SynchronizationContext.Current);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            cTokenSourceSql = new CancellationTokenSource();
            var tokenSqlData = cTokenSourceSql.Token;
            if (this._TaskSqlData != null)
            {
                if (this._TaskSqlData.Status == TaskStatus.Running)
                    this.cTokenSourceSql.Cancel();
                this._TaskSqlData.Dispose();
                this._TaskSqlData = null;
            }
            _TaskSqlData = Task.Factory.StartNew(()
                            => StartDoingWork(this, tokenSqlData, null), tokenSqlData);
        }

        public void StartDoingWork(object sender, CancellationToken ct, EventArgs e)
        {
            if (ct.IsCancellationRequested)
                ct.ThrowIfCancellationRequested();

            _work.DoSomeOtherWork();
        }
    }

    public class Message
    {
        private string messageSummary;
        public Message() { }
        public string MessageSummary
        {
            set { messageSummary = value; }
            get { return messageSummary; }
        }
    }

    public class WorkDoingClass
    {
        private SynchronizationContext _syncContext;

        public WorkDoingClass() { }

        public WorkDoingClass(SynchronizationContext _syncContext)
        {
            // TODO: Complete member initialization
            this._syncContext = _syncContext;
        }
        public void DoSomeWork()
        {
            //some routines
            Message messageObj = new Message();
            messageObj.MessageSummary = "DoSOmrWork Finished";
        }

        public void DoSomeOtherWork()
        {
            _syncContext.Send(DoWork, null);
        }

        private static void DoWork(object arg)
        {
            //some routines
            Message messageObj = new Message();
            messageObj.MessageSummary = "DoSomeOtherWork Finished";
            AllMessages.Instance.AllMessagesBindingList.Add(messageObj);
        }
    }

    public sealed class AllMessages
    {
        private static readonly AllMessages _instance = new AllMessages();
        private BindingList<Message> _allMessagesBL;

        public AllMessages() { _allMessagesBL = new BindingList<Message>(); }

        public static AllMessages Instance
        {
            get { return _instance; }
        }

        public BindingList<Message> AllMessagesBindingList
        {
            get { return _allMessagesBL; }
        }
    }
}
...