Example #1
0
        private void InitRichTextBoxRuntime()
        {
            if (IsInitialized)
            {
                throw new InvalidOperationException("The underlying RichTextBox has already been initialized.");
            }

            if (!IsHandleCreated)
            {
                base.CreateHandle();
            }

            // We can't pass our actual handle property to another thread, so we make a copy and pass that.
            if (_thisHandle == IntPtr.Zero)
            {
                _thisHandle = Handle;
            }

            // Note: a task gets closed automatically on regular shutdown, whereas a thread needs explicit cleanup
            // or Environment.Exit(). Tasks seem to work just as well and are easier to use, so I'm using a task
            // for now.
            if (_asyncTask == null)
            {
                _asyncTask = new Task(() =>
                {
                    // The RichTextBox is *created* on this thread, which is what allows it to be async, but we
                    // *declared* it on the main thread, which means we can still reference it, as long as we do
                    // it through an Invoke() or BeginInvoke().
                    // TODO: We shouldn't be setting ReadOnly here, but just for testing purposes
                    _richTextBoxInternal = new RichTextBox_CH {
                        ReadOnly = true, BackColor = SystemColors.Window
                    };

                    // And the same sort of setup with the ApplicationContext, just in case we want to call into
                    // it too
                    _asyncRTBAppContext = new RTB_AppContext(this, _richTextBoxInternal, _waitHandle);

                    // This starts a second message loop, which is what we want: the RichTextBox will have its
                    // own UI thread
                    Application.Run(_asyncRTBAppContext);
                });

                _asyncTask.Start();

                // We have to use signaling because we're not waiting for the task to finish, but only for the
                // ApplicationContext's constructor to finish. And besides, Application.Run() means the task will
                // never finish anyway.
                _waitHandle.WaitOne();

                // This is why we need to pass our handle and run CreateHandle() on the RichTextBox (see below);
                // this is what puts the RichTextBox inside our main UI (while still keeping it asynchronous)
                _richTextBoxInternal.Invoke(RTB_DockToUI, true);

                // "Set Dock to DockStyle.Fill" as it were
                _richTextBoxInternal.BeginInvoke(new Action(() => _richTextBoxInternal.Location = new Point(0, 0)));
                SetRichTextBoxSizeToFill();
            }

            IsInitialized = true;
        }
Example #2
0
        private void InitRichTextBoxDesignTime()
        {
            if (IsInitialized)
            {
                throw new InvalidOperationException("The underlying RichTextBox has already been initialized.");
            }

            _richTextBoxInternal = new RichTextBox_CH();
            Controls.Add(_richTextBoxInternal);
            _richTextBoxInternal.Dock = DockStyle.Fill;

            IsInitialized = true;
        }
Example #3
0
            internal RTB_AppContext(RichTextBoxAsync owner, RichTextBox_CH richTextBox, AutoResetEvent waitHandle)
            {
                _owner       = owner;
                _richTextBox = richTextBox;

                _richTextBox.KeyDown   += _richTextBox_KeyDown;
                _richTextBox.MouseDown += _richTextBox_MouseDown;

                // CreateHandle() is not exposed, so to get at it we have to subclass RichTextBox and expose it
                // ourselves. We could call CreateControl() which is exposed, but that will only work if the
                // control is visible, and we don't want to have to set it to visible right off the bat.
                if (!_richTextBox.IsHandleCreated)
                {
                    _richTextBox.CreateHandle();
                }

                // Notify the main thread that we're done initializing
                waitHandle.Set();
            }