Answered Combine multiple lines into a single line in a textbox

Govind Sankar

Active member
Joined
May 15, 2020
Messages
42
Programming Experience
Beginner
Hi,

I have a wpf application that has a textbox to which value is inserted using a scanner. At one time when I scan a single data, multiple lines comes into textbox which can be scrolled down to see. But I dont want them as multiple lines. I want to combine all lines into a single line and see in the textbox without scrolling. How can I do that. Thank You.
 
The Text property is a String like any other so you can split it on line breaks and then combine the resulting array in whatever way you want, then redisplay the final result.
 
What you are asking will very depending on the design of your elements and controls. In WPF, there are a few things you need to do to stop scrolling. First you should start off using : TextWrapping="NoWrap" - This only takes you so far, as now it will not breach and drop onto another line. It also won't stretch the control as the digits are appended. So the size of your control will decide the fate of how much of the text is displayed.

Additionally, you may want to add : HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
You should have some xaml which looks like this :
C#:
<TextBox Name="tbox1" Text="Test" VerticalContentAlignment="Center" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" TextWrapping="NoWrap" />

Lets know if this is what you are looking to do?
 
What you are asking will very depending on the design of your elements and controls. In WPF, there are a few things you need to do to stop scrolling. First you should start off using : TextWrapping="NoWrap" - This only takes you so far, as now it will not breach and drop onto another line. It also won't stretch the control as the digits are appended. So the size of your control will decide the fate of how much of the text is displayed.

Additionally, you may want to add : HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
You should have some xaml which looks like this :
C#:
<TextBox Name="tbox1" Text="Test" VerticalContentAlignment="Center" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" TextWrapping="NoWrap" />

Lets know if this is what you are looking to do?

No, still I am not getting it. I scan the QR code and this is what I get in the textbox.
SAR41-d1A3
5701/014
Cpa
01.04.2020

But what I want is SAR41-d1A35701/014Cpa01.04.2020 in the textbox. Unfortunately I cannot get it, till now. Kindly do help me.
 
What you are asking will very depending on the design of your elements and controls. In WPF, there are a few things you need to do to stop scrolling. First you should start off using : TextWrapping="NoWrap" - This only takes you so far, as now it will not breach and drop onto another line. It also won't stretch the control as the digits are appended. So the size of your control will decide the fate of how much of the text is displayed.

Additionally, you may want to add : HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
You should have some xaml which looks like this :
C#:
<TextBox Name="tbox1" Text="Test" VerticalContentAlignment="Center" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" TextWrapping="NoWrap" />

Lets know if this is what you are looking to do?
Also I want to tell you that I am using key down event for the textbox and when I scan the QR code, I am getting different lines one at a time and not all together and that is causing problems with key down handler because i think it is getting executed when each line is inserted.
 
Show me your code for the keydown event?

You can use split, and join to reform the text without line breaks.

C#:
 private void Unio_mod2_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                    string mod1_ctrl;
                    mod1_ctrl = unio_mod2.Text;
                    var ctrl = new Kontrolle_Scan();
                    // as you can see when I pass the mod1_ctrl to the other class
                    // then I want to pass it as single text with no spaces and as
                    // you can see mod1_ctrl gets its data from the textbox which is
                    // Unio_mod2.
                    ctrl.Auswertung_mod1(mod1_ctrl); // code for this can found below
                    var mod1_temp = ctrl.get_mod1_ctrl();
                
                    // rest is not important for you
                
                    //MessageBox.Show(mod1_temp.ToString());
                    int SK1count = ctrl.Karte1_existiert(mod1_ctrl);
                    //MessageBox.Show(SK1count.ToString());
                    //MessageBox.Show("Number of SK1 cards in UNIO DB is " + SK1count.ToString());
                    
                    if (SK1count != 0)
                    {
                        MessageBox.Show("Diese Signal Karte 1 wurde bereits in einem anderen UNIO-Modul verwendet");
                        unio_mod2.Text = "";
                    }
                    else
                    {
                        if (mod1_temp != 1 && mod1_temp != -1)
                        {
                            unio_mod2.Background = Brushes.Red;
                            const string caption = "Entscheidung akzeptiert.";
                            var result = System.Windows.Forms.MessageBox.Show(String.Format("Das eingescannte Modul ist nicht in den Datenbanken vorhanden. \nMöchten Sie das Modul trotzdem eintragen?"), caption, System.Windows.Forms.MessageBoxButtons.YesNo).ToString();

                            if (result == "No")
                            {
                                unio_mod2.Background = Brushes.White;
                                unio_mod2.Text = "";
                            }
                            else if (result == "Yes")
                            {
                                mod1_temp = 1;
                            }
                        }
                        
                        else if(mod1_temp == -1)
                        {
                            
                            unio_mod2.Text = "";
                            unio_mod2.Focus();                           
                        }
                        
                        else if (mod1_temp == 1)
                        {
                            if (unio_mod2.Text.Length >= 30 && unio_mod2.Text.Length <= 40 && unio_mod2.Text != unio_mod1.Text)
                            {
                                mod1 = unio_mod2.Text;
                                unio_mod2.Background = Brushes.Green;
                                unio_mod3.Focus();
                            }
                        }
  
              }

You can understand from this that Unio_mod2 is the textbox.

Kontrelle Scan is a different class and this is the code for that.
// This part is also not important. But just so that you can see
C#:
public void Auswertung_mod1(string mod1_temp)
        {
            DataGridAdapter_4AI.Fill(ds._4AI);
            DataGridAdapter_4AO.Fill(ds._4AO);
            DataGridAdapter_2AI2AO.Fill(ds._2AI2AO);
            DataGridAdapter_PT100.Fill(ds.PT100);
            
            if (mod1_temp.Substring(0, 3)== "SAR" || mod1_temp.Length<13)
            {
                MessageBox.Show("Sie haben den falschen Code gescannt. \nBitte scannen Sie den korrekten Datenmatrizencode");
                mod1 = -1;
            }
            else
            {
                string filter_mod1 = mod1_temp.Substring(13, 6);
                var temp1 = ds._4AI.Where(o => o.Herstellerseriennummer == filter_mod1).Count();
                var temp2 = ds._4AO.Where(o => o.Herstellerseriennummer == filter_mod1).Count();
                var temp3 = ds._2AI2AO.Where(o => o.Herstellerseriennummer == filter_mod1).Count();
                var temp4 = ds.PT100.Where(o => o.Herstellerseriennummer == filter_mod1).Count();
                mod1 = temp1 + temp2 + temp3 + temp4;
            }                 
        }

The code is a bit complicated as you can see. This code is a part of a bigger program.
 
Show me your code for the keydown event?

You can use split, and join to reform the text without line breaks.
C#:
string[] lines = unio_mod2.Text.Split('\n');
MessageBox.Show(lines[0]);

I just used this code inside the keydown event handler. So remember I told you the output from scanning the qr code is
SAR41-d1A3
5701/014
Cpa
01.04.2020.

So I expect this to happen
lines[0] = SAR41-d1A3
lines[1] = 5701/014
lines[2] = Cpa
lines[3] = 01.04.2020

and SAR41-d1A3 should be the one Messagebox must be showing. That is what I expect.

But the Messagebox is showing 01.04.2020 which. Also I am seeing a brief flash of another messagebox appearing and going before this messagebox. So I am assuming first line is stored in line[0], then it is removed and the second line is stored in line[0] again and so on and the final one we can see. So this is my main problem. Each line coming seperately.
 
Show me your code for the keydown event?

You can use split, and join to reform the text without line breaks.
I also want to say the above problem is when I set AcceptsReturn ="False". When I set it to True then multiline is allowed. Then the key down event handler is not working as I can just see the multiple line in the textbox and nothing else is happening.
 
I have created a simple program that has a texbox which accepts text from scanning a qr code. This is the textbox.

C#:
<TextBox x:Name="LearnTextBox" HorizontalAlignment="Left" Height="23" Margin="83,173,0,0" VerticalAlignment="Top" Width="620" Cursor="Pen" MaxLength="39" AcceptsReturn="True" KeyDown="LearnTextBox_KeyDown">
        </TextBox>

As u can see I have set AcceptsReturn = "True" which means multiple lines are allowed. Now for the actual code its just a simple keydown even. So when the keydown event happens the text from textbox is stored in a string variable and
then displayed using a messagebox.

C#:
namespace LearnTextboxKeyDownEvent
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            LearnTextBox.Focus();
        }
        private void LearnTextBox_KeyDown(object sender, KeyEventArgs e)
        {
           
            if(e.Key == Key.Return)
            {
                string text = LearnTextBox.Text;              
                MessageBox.Show(text);
            }
        }
    }
}

Now the problem is when AcceptsReturn = "True" then LearnTextBox_KeyDown event is not occuring. Nothing is happening. AcceptsReturn = "False", then key down event works if the QR code gives a single line of text. But if it is multi line, multiple messageboxes come one after the other and go away in a second, so something like a flash of it happening can be seen. I want to set AcceptsReturn = "True" and then an event should be handled for that. If it is not the key down event, then which event should I use. Kindly do help me.
 
Last edited by a moderator:
First, I'm going to assume that the reason why you are letting the scanner run as keyboard driver is because you don't have the SDK to access the scanner data directly. So that means when you hit the trigger on the scanner gun, you are letting it emulate typing into the keyboard. If this is going to be an ongoing project, I would recommend contacting the manufacturer of your scanner and see if you can a copy of the SDK at best, or a copy of the source code for their Windows drivers at worse and then get the data directly from the scanner.

Second, as you've discovered trying to process the input right away when you see the Return key come in is not getting you what you need. I would suggest a different approach. Something like this pseudo code:
C#:
// In view code:

public ScannerInputTextBox : TextBox
{

public event EventHandler DataReady;

ScannerInputTextBox()
    : base()
{
    :
    isWaitingForInput = true;
    timer = new DispatcherTimer();
    timer.Tick += (o,e) => FireDataReadyEvent();
    timer.Interval = TimeSpan.FromSeconds(1);     // wait for input to complete in 1 second
}

OnTextChange()
{
    if (!isWaitingForInput)
        return;

    // reset the timer to keep waiting
    timer.Stop();
    timer.Start();
}

FireDataReadyEvent()
{
    isWaitingForInput = false;
    timer.Stop();
    DataReady?.Invoke(...);
    isWaitingForInput = true;
}

}    // end of custom ScannerInputTextBox control

// In your view model code:

InputViewModel()
{
    scannerInputTextBox.DataReady += (o, e) => OnDataReady;
}

OnDataReady()
{
    var fourLineText = scannerInputTextBox.Text.Split('\n');
    var joinedText = string.Join("", fourLineText);
    scannerInputTextBox.Text = joinedText;
    
    // do rest of processing of joinedText to do your database queries, etc.
}

What the pseudo code above does is that it assumes that you derive a class from the text box and add a new DataReady event. The custom textbox then waits for text change events and starts a timer. If more input keeps coming in rapidly, the timer is reset. If no more input comes in, the timer expires, and the DataReady event is fired. Then in your page code that contains that custom control, you wait for the DataReady event. When it fires, then you can do the splitting and joining of the 4 lines into a single line, as well as do the rest of your data processing.

As an aside, why are you writing WPF code as if you were writing WinForms code?
 
First, I'm going to assume that the reason why you are letting the scanner run as keyboard driver is because you don't have the SDK to access the scanner data directly. So that means when you hit the trigger on the scanner gun, you are letting it emulate typing into the keyboard. If this is going to be an ongoing project, I would recommend contacting the manufacturer of your scanner and see if you can a copy of the SDK at best, or a copy of the source code for their Windows drivers at worse and then get the data directly from the scanner.

Second, as you've discovered trying to process the input right away when you see the Return key come in is not getting you what you need. I would suggest a different approach. Something like this pseudo code:
C#:
// In view code:

public ScannerInputTextBox : TextBox
{

public event EventHandler DataReady;

ScannerInputTextBox()
    : base()
{
    :
    isWaitingForInput = true;
    timer = new DispatcherTimer();
    timer.Tick += (o,e) => FireDataReadyEvent();
    timer.Interval = TimeSpan.FromSeconds(1);     // wait for input to complete in 1 second
}

OnTextChange()
{
    if (!isWaitingForInput)
        return;

    // reset the timer to keep waiting
    timer.Stop();
    timer.Start();
}

FireDataReadyEvent()
{
    isWaitingForInput = false;
    timer.Stop();
    DataReady?.Invoke(...);
    isWaitingForInput = true;
}

}    // end of custom ScannerInputTextBox control

// In your view model code:

InputViewModel()
{
    scannerInputTextBox.DataReady += (o, e) => OnDataReady;
}

OnDataReady()
{
    var fourLineText = scannerInputTextBox.Text.Split('\n');
    var joinedText = string.Join("", fourLineText);
    scannerInputTextBox.Text = joinedText;
   
    // do rest of processing of joinedText to do your database queries, etc.
}

What the pseudo code above does is that it assumes that you derive a class from the text box and add a new DataReady event. The custom textbox then waits for text change events and starts a timer. If more input keeps coming in rapidly, the timer is reset. If no more input comes in, the timer expires, and the DataReady event is fired. Then in your page code that contains that custom control, you wait for the DataReady event. When it fires, then you can do the splitting and joining of the 4 lines into a single line, as well as do the rest of your data processing.

As an aside, why are you writing WPF code as if you were writing WinForms code?
Thank You. I will try to implement this and get back in case of any queries which I am sure I will have since I am just a beginner in C# and WPF.
 
First, I'm going to assume that the reason why you are letting the scanner run as keyboard driver is because you don't have the SDK to access the scanner data directly. So that means when you hit the trigger on the scanner gun, you are letting it emulate typing into the keyboard. If this is going to be an ongoing project, I would recommend contacting the manufacturer of your scanner and see if you can a copy of the SDK at best, or a copy of the source code for their Windows drivers at worse and then get the data directly from the scanner.

Second, as you've discovered trying to process the input right away when you see the Return key come in is not getting you what you need. I would suggest a different approach. Something like this pseudo code:
C#:
// In view code:

public ScannerInputTextBox : TextBox
{

public event EventHandler DataReady;

ScannerInputTextBox()
    : base()
{
    :
    isWaitingForInput = true;
    timer = new DispatcherTimer();
    timer.Tick += (o,e) => FireDataReadyEvent();
    timer.Interval = TimeSpan.FromSeconds(1);     // wait for input to complete in 1 second
}

OnTextChange()
{
    if (!isWaitingForInput)
        return;

    // reset the timer to keep waiting
    timer.Stop();
    timer.Start();
}

FireDataReadyEvent()
{
    isWaitingForInput = false;
    timer.Stop();
    DataReady?.Invoke(...);
    isWaitingForInput = true;
}

}    // end of custom ScannerInputTextBox control

// In your view model code:

InputViewModel()
{
    scannerInputTextBox.DataReady += (o, e) => OnDataReady;
}

OnDataReady()
{
    var fourLineText = scannerInputTextBox.Text.Split('\n');
    var joinedText = string.Join("", fourLineText);
    scannerInputTextBox.Text = joinedText;
   
    // do rest of processing of joinedText to do your database queries, etc.
}

What the pseudo code above does is that it assumes that you derive a class from the text box and add a new DataReady event. The custom textbox then waits for text change events and starts a timer. If more input keeps coming in rapidly, the timer is reset. If no more input comes in, the timer expires, and the DataReady event is fired. Then in your page code that contains that custom control, you wait for the DataReady event. When it fires, then you can do the splitting and joining of the 4 lines into a single line, as well as do the rest of your data processing.

As an aside, why are you writing WPF code as if you were writing WinForms code?
Hi,

I am trying to implement this. But my knowledge in C# is limited to the basic programming that is present in c++, java etc. So these topics are new to me. So i have to learn them to implement them. Can you suggest me what all I have to know or what all I have to learn to implement this. I have been trying to search for a good tutorial that teaches how to create a custom textbox online. But I am not able to find it. So please let me know what all should I learn. Thank You.
 
In C++ and Java there is the concept of inheritance. That's all you need to do: inherit from the TextBox control and add your custom stuff.
 
Back
Top Bottom