C# 捕获用户单击并在自定义WPF文本框中键入控件?

C# 捕获用户单击并在自定义WPF文本框中键入控件?,c#,wpf,custom-controls,C#,Wpf,Custom Controls,尝试在C#和WPF中的Microsoft Word中制作这样的公式编辑器。不能使用XML;它必须是纯程序性的 现在我有了LineGUIObject:System.Windows.Controls.WrapPanel,它类似于System.Windows.Controls.TextBox,只是它不只是显示字符串,而是按顺序显示列表的每个元素 现在,我希望用户能够单击LineGUIObject的实例并在其中键入内容。问题是我不知道如何捕捉用户的点击或读取他们输入的内容。如何做到这一点 注意:这个问题

尝试在C#和WPF中的Microsoft Word中制作这样的公式编辑器。不能使用XML;它必须是纯程序性的

现在我有了
LineGUIObject:System.Windows.Controls.WrapPanel
,它类似于
System.Windows.Controls.TextBox
,只是它不只是显示字符串,而是按顺序显示
列表的每个元素

现在,我希望用户能够单击
LineGUIObject
的实例并在其中键入内容。问题是我不知道如何捕捉用户的点击或读取他们输入的内容。如何做到这一点

注意:这个问题不是询问一旦捕获,如何处理输入;首先是如何获得输入。例如,是否存在某个
事件
,在用户单击该事件或其他事件后触发?我似乎找不到适用于
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; } }
}
公共类LineGUIObject
:System.Windows.Controls.WrapPanel
{
私有列表uiElementList;
私有游标orguiobject\u游标;
私人综合指数;
公用LineGUIObject(System.Windows.Threading.Dispatcher)
:base()
{
this.UIElementList=新列表();
Cursor=newcursorguiobject(dispatcher,25,1.5250);
this.UIElementList.Add(this.Cursor);
this.AddText(“[junk string,仅在调试时看到此不可见的对象]”;
}
受保护的用户击键(/*???*/)
{
//我们如何在用户输入时调用此方法,
//e、 g.当用户键入“1”时?
抛出新的NotImplementedException();
}
受保护的无效添加文本(字符串文本)
{
this.UIElementList.Add(new System.Windows.Controls.TextBlock(new System.Windows.Documents.Run(text));
this.UpdateDisplay();
}
受保护列表UIElementList{get{返回此。UIElementList;}私有集{this。UIElementList=value;}}
受保护的CursorGUIObject游标{get{返回此。_Cursor;}私有集{this。_Cursor=value;}}
受保护的整数?游标索引
{
获取{返回此。\u cursorIndex;}
设置
{
int?nullablePriorIndex=this.CursorIndex;
if(nullablePriorIndex!=null)
{
int priorIndex=nullablePriorIndex.Value;
this.UIElementList.RemoveAt(priorIndex);
}
如果(值==null)
{
这是.\u cursorIndex=null;
}
其他的
{
int newIndex=value.value;
如果(新索引<0)
{
newIndex=0;
}
其他的
{
int thisListCount=this.UIElementList.Count;
如果(newIndex>thisListCount){newIndex=thisListCount;}
}
this.UIElementList.Insert(newIndex,this.Cursor);
这是.\u cursorIndex=newIndex;
}
this.UpdateDisplay();
}
}
受保护的void UpdateDisplay()
{
这个.Children.Clear();
foreach(System.Windows.UIElement在此.UIElement列表中的UIElement){this.Children.Add(UIElement);}
}
}
公共类CursorGUIObject
:System.Windows.Controls.WrapPanel
{
公共常数双倍最小闪烁时间(单位:毫秒)=5;
公共建筑双倍最小高度=0.5;
公共建筑双最小宽度=0.5;
private object ToggleVisibilityLock=新对象();
私有委托void TimerIntervalDelegate();
private System.Windows.Shapes.Rectangle\u Rectangle;
专用系统.Timers.Timer\u定时器;
private System.Windows.Threading.Dispatcher\u Dispatcher;
公共游标OrguiObject(System.Windows.Threading.Dispatcher Dispatcher,双高、双宽、双闪烁时间inms)
{
this.Dispatcher=Dispatcher;
System.Windows.Shapes.Rectangle矩形=新的System.Windows.Shapes.Rectangle();
矩形。宽度=宽度>最小宽度?宽度:最小宽度;
矩形。高度=高度>最小高度?高度:最小高度;
矩形.Fill=System.Windows.Media.brusks.Black;
这个矩形=矩形;
this.Children.Add(矩形);
System.Timers.Timer Timer=新的System.Timers.Timer(闪烁时间单位毫秒>最小闪烁时间单位毫秒?闪烁时间单位毫秒:最小闪烁时间单位毫秒);
this.Timer=计时器;
timer.appeated+=timer\u appeated;
timer.Start();
}
~CursorGUIObject()
{
System.Timers.Timer Timer=此.Timer;
如果(timer!=null){timer.Dispose();}
}
私有无效计时器(对象发送器,System.Timers.ElapsedEventArgs e)
{
委托timerDelegate=新的TimerIntervalDelegate(切换可见性);
this.Dispatcher.BeginInvoke(timerDelegate);
}
受保护的void ToggleVisibility()
{
锁定(切换可见性锁定)
{
if(this.Rectangle.Visibility.Equals(System.Windows.Visibility.Hidden))
{
this.Rectangle.Visibility=System.Windows.Visibility.Visible;
}
其他的
{
this.Rectangle.Visibility=System.Windows.Visibility.Hidden;
}
}
}
受保护的System.Windows.Shapes.Rectangle矩形{获取{返回此。_Rectangle;}私有集{此。_Rectangle=value;}
受保护的System.Timers.Timer Timer{get{返回此。_Timer;}私有集{此。_Timer=value;}
受保护的System.Windows.Threading.Dispatcher调度程序{获取{返回此。_Dispatcher;}私有集{此。_Dispatcher=value;}
}

结果是
LineGUIObject
只需要
this.Focusable=true在其构造函数中设置,因此
    protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
    {
        this.AddText(e.Key.ToString());
    }
<Popup Name="Popup">
    <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5" Padding="5">
        <TextBox Text="{Binding InputText}" />
    </Border>
</Popup>
private void YourObject_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    Popup.IsOpen = true;
}