簡體   English   中英

捕獲用戶單擊並鍵入自定義的類似WPF TextBox的控件?

[英]Capture user click and typing in a custom WPF TextBox-like control?

試圖用C#和WPF在Microsoft Word中創建一個方程式編輯器。 不能使用XML。 它必須純粹是程序性的。

現在,我有LineGUIObject : System.Windows.Controls.WrapPanel ,類似於System.Windows.Controls.TextBox ,除了它不只是顯示字符串,而是按順序顯示List<System.Windows.UIElement>每個元素。

現在,我希望用戶能夠單擊LineGUIObject的實例並將其鍵入。 原因是我不知道如何捕獲用戶的點擊或閱讀他們鍵入的輸入。 如何才能做到這一點?

注意:這個問題不是在捕獲輸入后詢問如何處理; 只是如何獲得輸入。 例如,是否有一些event在用戶單擊后觸發? 我似乎找不到用於System.Windows.Controls.WrapPanel ,這可能意味着我需要使用另一種對象,或者..?

當前代碼:

public class LineGUIObject
    :   System.Windows.Controls.WrapPanel
{
    private List<System.Windows.UIElement> _uiElementList;
    private CursorGUIObject _cursor;
    private int? _cursorIndex;
    public LineGUIObject(System.Windows.Threading.Dispatcher dispatcher)
        : base()
    {
        this.UIElementList = new List<System.Windows.UIElement>();
        this.Cursor = new CursorGUIObject(dispatcher, 25, 1.5, 250);
        this.UIElementList.Add(this.Cursor);

        this.AddText("[junk string just to see this otherwise invisible object while debugging]");
    }
    protected void InterpretUserKeyStroke(/* ??? */)
    {
        //How do we get this method to be called on user input,
        //e.g. when the user types "1"?
        throw new NotImplementedException();
    }
    protected void AddText(string text)
    {
        this.UIElementList.Add(new System.Windows.Controls.TextBlock(new System.Windows.Documents.Run(text)));
        this.UpdateDisplay();
    }
    protected List<System.Windows.UIElement> UIElementList { get { return this._uiElementList; } private set { this._uiElementList = value; } }
    protected CursorGUIObject Cursor { get { return this._cursor; } private set { this._cursor = value; } }
    protected int? CursorIndex
    {
        get { return this._cursorIndex; }
        set
        {
            int? nullablePriorIndex = this.CursorIndex;

            if (nullablePriorIndex != null)
            {
                int priorIndex = nullablePriorIndex.Value;
                this.UIElementList.RemoveAt(priorIndex);
            }

            if (value == null)
            {
                this._cursorIndex = null;
            }
            else
            {
                int newIndex = value.Value;
                if (newIndex < 0)
                {
                    newIndex = 0;
                }
                else
                {
                    int thisListCount = this.UIElementList.Count;
                    if (newIndex > thisListCount) { newIndex = thisListCount; }
                }

                this.UIElementList.Insert(newIndex, this.Cursor);
                this._cursorIndex = newIndex;
            }

            this.UpdateDisplay();
        }
    }

    protected void UpdateDisplay()
    {
        this.Children.Clear();
        foreach (System.Windows.UIElement uiElement in this.UIElementList) { this.Children.Add(uiElement); }
    }
}


public class CursorGUIObject
    :   System.Windows.Controls.WrapPanel
{
    public const double MINIMUM_BLINK_TIME_IN_MS = 5;
    public const double MINIMUM_HEIGHT = 0.5;
    public const double MINIMUM_WIDTH = 0.5;

    private object ToggleVisibilityLock = new object();

    private delegate void TimerIntervalDelegate();

    private System.Windows.Shapes.Rectangle _rectangle;
    private System.Timers.Timer _timer;
    private System.Windows.Threading.Dispatcher _dispatcher;
    public CursorGUIObject(System.Windows.Threading.Dispatcher dispatcher, double height, double width, double blinkTimeInMS)
    {
        this.Dispatcher = dispatcher;

        System.Windows.Shapes.Rectangle rectangle = new System.Windows.Shapes.Rectangle();
        rectangle.Width = width > MINIMUM_WIDTH ? width : MINIMUM_WIDTH;
        rectangle.Height = height > MINIMUM_HEIGHT ? height : MINIMUM_HEIGHT;
        rectangle.Fill = System.Windows.Media.Brushes.Black;
        this.Rectangle = rectangle;
        this.Children.Add(rectangle);

        System.Timers.Timer timer = new System.Timers.Timer(blinkTimeInMS > MINIMUM_BLINK_TIME_IN_MS ? blinkTimeInMS : MINIMUM_BLINK_TIME_IN_MS);
        this.Timer = timer;
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }
    ~CursorGUIObject()
    {
        System.Timers.Timer timer = this.Timer;
        if (timer != null) { timer.Dispose(); }
    }
    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Delegate timerDelegate = new TimerIntervalDelegate(ToggleVisibility);
        this.Dispatcher.BeginInvoke(timerDelegate);
    }
    protected void ToggleVisibility()
    {
        lock (ToggleVisibilityLock)
        {
            if (this.Rectangle.Visibility.Equals(System.Windows.Visibility.Hidden))
            {
                this.Rectangle.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                this.Rectangle.Visibility = System.Windows.Visibility.Hidden;
            }
        }
    }
    protected System.Windows.Shapes.Rectangle Rectangle { get { return this._rectangle; } private set { this._rectangle = value; } }
    protected System.Timers.Timer Timer { get { return this._timer; } private set { this._timer = value; } }
    protected System.Windows.Threading.Dispatcher Dispatcher { get { return this._dispatcher; } private set { this._dispatcher = value; } }
}

幾乎所有WPF控件都提供對UIElement.PreviewMouseDown事件的訪問,您可以使用它來監視鼠標單擊。 因此,此事件使您可以監視何時單擊每個對象。 接下來,建議您使用一個小的Popup控件來彈出一個TextBox ,用戶可以使用以下命令輸入值:

<Popup Name="Popup">
    <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5" Padding="5">
        <TextBox Text="{Binding InputText}" />
    </Border>
</Popup>

根據您如何設置項目,您可以從事件處理程序中打開Popup窗口:

private void YourObject_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Popup.IsOpen = true;
}

原來LineGUIObject只需要具有this.Focusable = true; 在其構造函數中進行設置,以便單擊時可以接收鍵盤的焦點。

現在可以重點關注了this.KeyUp += LineGUIObject_KeyUp; 同樣在構造函數中

    protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
    {
        this.AddText(e.Key.ToString());
    }

因為我的LineGUIObject嵌套在ScrollViewer ,所以即使這樣一開始也是有問題的,它在LineGUIObject收到它之后立即一直在竊取焦點。 通過使ScrollViewer無法獲得焦點來解決此問題,即<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Focusable="False"/>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM