I have made a simple TO-DOs program that gets input from a text box then place it in another text box. With tick boxes next to it,
this is all fine except i Cannot save the list eg. the item and if it's finished or not.
Please could anyone help me be able to save this list of items.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TO_DOs
{
public partial class Form1 : Form
{
private bool text1, text2, text3, text4, text5, text6, text7, text8;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (text1 == false)
{
textBox2.Text = textBox1.Text;
}
else if (text2 == false)
{
textBox3.Text = textBox1.Text;
}
else if (text3 == false)
{
textBox4.Text = textBox1.Text;
}
else if (text4 == false)
{
textBox5.Text = textBox1.Text;
}
else if (text5 == false)
{
textBox6.Text = textBox1.Text;
}
else if (text6 == false)
{
textBox7.Text = textBox1.Text;
}
else if (text7 == false)
{
textBox8.Text = textBox1.Text;
}
else if (text8 == false)
{
textBox9.Text = textBox1.Text;
}
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
text1 = true;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
text2 = true;
}
private void textBox4_TextChanged(object sender, EventArgs e)
{
text3 = true;
}
private void textBox5_TextChanged(object sender, EventArgs e)
{
text4 = true;
}
private void textBox6_TextChanged(object sender, EventArgs e)
{
text5 = true;
}
private void textBox7_TextChanged(object sender, EventArgs e)
{
text6 = true;
}
private void textBox8_TextChanged(object sender, EventArgs e)
{
text7 = true;
}
private void textBox9_TextChanged(object sender, EventArgs e)
{
text8 = true;
}
}
}
I would do it like this:
Create a class to store your values in:
public class ListEntry
{
public string Text { get; set; }
public bool Finished { get; set; }
}
Then I would create 2 Methods:
public List<ListEntry> UI_To_List(); //Create UI from your saved file
public void List_To_UI(List<ListEntry> entries); //Process your UI
Now it's your choice on how to store your list.
You could store it as JSON or XML.
A few recommendations:
I would create a UserControl for your TextBox + CheckBox
Display the 'List of UserControls' in a FlowLayoutPanel
=> then you can process the FlowLayoutPanel.Controls List.
This will make your List dynamically size to an 'unlimited' amount of items.
Short example:
Create a UserControl (Rightclick project for that):
Add these 2 methods to the code of your UserControl (F7 / rightclick => View Code):
public void SetText(string text)
{
//Set the Text of your TextBox in the UserControl:
textBox1.Text = text;
}
public void SetFinished(bool finished)
{
//Set the Checked of your CheckBox in the UserControl:
checkBox1.Checked = finished;
}
In your MainForm add an FlowLayoutPanel (from ToolBox).
Add your Data like this (using class from above):
/// <summary>
///
/// </summary>
/// <param name="entries">You will get them from loading your previously saved file</param>
public void CreateUI(List<ListEntry> entries)
{
foreach (ListEntry entry in entries)
{
//Create new instance of your UserControl
TaskView view = new TaskView();
view.SetFinished(entry.IsFinished);
view.SetText(entry.Text);
//Add that to your UI:
this.flowLayoutPanel1.Controls.Add(view);
}
}
The result will look like this:
I'm not sure what exactly it is that you want to save in a list... but here's just a tip when checking conditions, instead of using if (text1 == false), simply do if (!text1) as this means "is not true" because by default if (text1) will return true.
private void button1_Click(object sender, EventArgs e)
{
if (!text1)
{
textBox2.Text = textBox1.Text;
}
else if (!text2)
{
textBox3.Text = textBox1.Text;
}
// Left out the rest of the else ifs
}
You are casting textboxes wrong. For example when you change textBox4, you gave text3 true.
private void textBox4_TextChanged(object sender, EventArgs e)
{
text3 = true;
}
Then you cast
TextBox4.Text = TextBox1.Text;
It changes TextBox4.Text to TextBox1.Text.
You probably want to save TextBox4.Text here at TextBox1.Text so you sould change all if blocks like that. So you have to give only one "true" function for changed textBox sign and change if blocks
if(text(boolNum))
TextBox1.Text = TextBox(Number).Text;
Just swap them and try like that.
If you want to save another thing by another way. You have to be more spesific.
You can use a CheckedListbox to hold all tot actions.
You can then tick the itemsand for instance in the OK button you include a save action:
foreach(var item in MyCheckedListbox.CheckedItems)
{
Console,WriteLine(item.Text);
}
Lets see the answer from Felix D. He tells you exactly how to create a class and save the items into it. But now you only have a List that will be available as long as your software is running. You still need to save it somewhere on your desktop.
Lucky for you, you got a really simple pattern.
string; boolean
So how about you make it yourself simple? Just create a textfile and write your entries, as example in a csv marked with a ; for every information?
Example:
class Program
{
public class tmpClass
{
public string Text;
public bool tick;
}
public List<tmpClass> tmpList = new List<tmpClass>();
static void Main(string[] args)
{
//Stuff
}
public void WriteToFile()
{
string tmpTextFilePath = #"C:\User\Desktop\SaveText.txt";
using (StreamWriter tmpWriter = new StreamWriter(tmpTextFilePath))
{
string tmpTextToWrite = String.Empty;
for (int i = 0; i < tmpList.Count; i++)
{
tmpClass tmpEntry = tmpList[i];
tmpTextToWrite += tmpEntry.Text + ";" + tmpEntry.tick;
}
tmpWriter.WriteLine(tmpTextToWrite);
}
//Now we wrote a text file to you desktop with all Informations
}
public void ReadFromFile()
{
string tmpTextFilePath = #"C:\User\Desktop\SaveText.txt";
using (StreamReader tmpReader = new StreamReader(tmpTextFilePath))
{
string tmpText = tmpReader.ReadLine();
string tmpInput = String.Empty;
tmpClass tmpClass = new tmpClass();
int i = 0;
foreach (char item in tmpText)
{
if(item.Equals(";".ToCharArray()))
{
if (i == 0)
{
tmpClass.Text = tmpInput;
i = 1;
tmpInput = String.Empty;
}
else
{
if (tmpInput == "True")
tmpClass.tick = true;
else
tmpClass.tick = false;
i = 0;
tmpInput = String.Empty;
tmpList.Add(tmpClass);
}
}
tmpInput += item;
}
}
}
}
This should simply write a txt File to your desktop with your information and read one and save it to your list.
Related
I have 2 forms: Game and newPlayer. When you press a button in Game, it opens the dialog of the newPlayer form, where someone would type his/her name and choose a Color in a comboBox between red, green, blue or yellow. I save that information in 2 variables: name (string) and color (int - being the index of the comboBox). I want to pass those 2 variables to the form Game.
I've tried unifying them in just one string and pass just one variabe to Game form, without success.
public partial class Game : Form
{
static int nPlayers = 4;
static List<Player> players = new List<Player>();
public string name = "";
private void button3_Click(object sender, EventArgs e)
{
using (newPlayer np = new newPlayer())
{
if (np.ShowDialog() == DialogResult.OK)
{
this.name = np.TheValue;
}
}
MessageBox.Show("Welcome " + name + "!");
}
and then:
public partial class newPlayer : Form
{
public string name = "";
public string TheValue
{
get { return this.name; }
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text != "")
{
if (comboBox1.SelectedIndex > -1)
{
this.name = textBox1.Text + comboBox1.SelectedIndex.ToString();
MessageBox.Show(newPlayer.name);
this.Close();
} else
{
MessageBox.Show("Write your name and choose a color!");
}
} else
{
MessageBox.Show("Write your name and choose a color!");
}
}
On the MessageBox of newPlayer it appears correctly like "Name1", for example. But on the MessageBox of Game, it appears empty. Can someone help, please?
You have forgotten to set the DialogResult when closing the form.
Try this:
this.DialogResult = DialogResult.OK;
this.Close();
If I were writing this code I might have done it more like this:
Game:
public partial class Game : Form
{
public Game()
{
InitializeComponent();
}
private string _playerName = "";
private void button3_Click(object sender, EventArgs e)
{
using (NewPlayer np = new NewPlayer())
{
if (np.ShowDialog() == DialogResult.OK)
{
_playerName = np.PlayerName;
MessageBox.Show($"Welcome {_playerName}!");
}
}
}
}
NewPlayer:
public partial class NewPlayer : Form
{
public NewPlayer()
{
InitializeComponent();
}
private string _playerName = "";
public string PlayerName
{
get { return _playerName; }
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text != "" && comboBox1.SelectedIndex > -1)
{
_playerName = $"{textBox1.Text}{comboBox1.SelectedIndex}";
MessageBox.Show(_playerName);
this.DialogResult = DialogResult.OK;
this.Close();
}
else
{
MessageBox.Show("Write your name and choose a color!");
}
}
}
I have these textboxes named bags,rate,quantity,packing size and amount what i want to do is that when user enters bags and rate and packing size the quantity textbox should automatically shows the corresponding quantity and amount but in my case when i click on calculate button then it calculates and show the quantity and amount i have tried using textchanged event but it does not do the job?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Login
{
public partial class Sale : Form
{
SaleCalci sale;
SaleBillheader SaleHeaderModel = new SaleBillheader();
tbl_SaleBillDetails SaleDetailModel = new tbl_SaleBillDetails();
public Sale()
{
InitializeComponent();
}
private void Cancelbtn_Click(object sender, EventArgs e)
{
clear();
}
private void clear()
{
txtBillNo.Text = txtDesc.Text = "";
txtBags.Text = txtQty.Text = txtRate.Text = txtAmt.Text = "0.00";
if(txtQty.Text !=null && txtAmt.Text !=null )
{
txtQty.Text = "0.00";
txtAmt.Text = "0.00";
}
Savebtn.Text = "Save";
SaleHeaderModel.SaleBillHeaderId = 0;
SaleDetailModel.SaleBill_Id = 0;
}
private void Exitbtn_Click(object sender, EventArgs e)
{
var result = MessageBox.Show("Are you sure you want to close this form ?", "Confirm", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{ this.Close(); }
}
private void Sale_Load(object sender, EventArgs e)
{
ItemCombo();
PartyCombo();
PackingSizeCombo();
// clear();
}
private void ItemCombo()
{
UserDataEntities db = new UserDataEntities();
Itembox.DataSource = db.tbl_ItemId.ToList();
Itembox.ValueMember = "ItemId";
Itembox.DisplayMember = "ItemName";
}
private void PartyCombo()
{
UserDataEntities db = new UserDataEntities();
PartyBox.DataSource = db.tbl_Parties.ToList();
PartyBox.ValueMember = "Id";
PartyBox.DisplayMember = "PartyName";
}
private void PackingSizeCombo()
{
UserDataEntities db = new UserDataEntities();
PackingBox.DataSource = db.PackingSizes.ToList();
PackingBox.ValueMember = "PackingSizeId";
PackingBox.DisplayMember = "PackingSize1";
}
private void Savebtn_Click(object sender, EventArgs e)
{
CalculateAmount();
DisplayAmt();
}
private void CalculateAmount()
{
int bags = 0;
decimal rate = 0;
int pksize = 0;
bags = Convert.ToInt32(txtBags.Text);
rate = Convert.ToDecimal(txtRate.Text);
pksize = Convert.ToInt32(PackingBox.Text);
sale = new SaleCalci(bags,rate, pksize);
//sale.Bags = Convert.ToInt32(txtBags.Text);
//sale.Rate = Convert.ToDecimal(txtRate.Text);
//SaleDetailModel.Bags = int.Parse(txtBags.Text.Trim());
//SaleDetailModel.Qty = Convert.ToDecimal(txtQty.Text.Trim());
//SaleDetailModel.Rate = Convert.ToDecimal(txtRate.Text.Trim());
// SaleDetailModel.Amount = amount;
}
private void txtAmt_TextChanged(object sender, EventArgs e)
{
// txtAmt.Text = sale.CalucalteAmt.ToString();
}
private void Sale_Click(object sender, EventArgs e)
{
if ((txtBags.Text == "0.00") && (txtQty.Text == "0.00")&&(txtRate.Text == "0.00")&& (txtAmt.Text =="0.00"))
{
txtAmt.Clear();
txtBags.Clear();
txtQty.Clear();
txtRate.Clear();
}
}
private void txtQty_TextChanged(object sender, EventArgs e)
{
DisplayAmt();
}
private void txtBags_TextChanged(object sender, EventArgs e)
{
// sale.Bags = Convert.ToInt32(txtBags.Text);
// DisplayAmt();
}
private void PackingBox_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void txtRate_TextChanged(object sender, EventArgs e)
{
// DisplayAmt();
}
private void DisplayAmt()
{
decimal _amt = sale.CalucalteAmt;
txtQty.Text = sale.CalculateQty().ToString();
txtAmt.Text = _amt.ToString();
}
}
}
Normally "TextChanged" event fires autamatically if text value changes.
So here the problem is i think about your other "partial class" in which there has to exist eventhandler work. Something like:
txtBags.TextChanged += new EventHandler(txtBags_TextChanged);
Please check your other partial class if this staement exist.
This eventhandler sometimes disappears from project if you move your gui elements or for some other causes...
You can readd this statement manually.
By the way if you have not experience with the other partial class then you can try to remove these textboxes and re-add them then your problem will autamatically solves.
You need to call DisplayAmt in the TextChanged event of txtBags , txtRate and Size. In the code above, call to DisplayAmt is commented out. Instead, you are calling DisplayAmt in the TextChanged event of txtQty.
You should be, instead doing.
private void txtAmt_TextChanged(object sender, EventArgs e)
{
DisplayAmt();
}
private void txtRate_TextChanged(object sender, EventArgs e)
{
DisplayAmt();
}
Similarly, you need to add Changed event for Text Control for Size. The txtQty is updated by the DisplayAmt() method. So you don't necessarily need it, unless for reasons that are not specified in OP.
So my program is a simple form that a user has to read, agree to the terms, and close the window. When the user closes the window it takes their login name and date / time, writes it to a txt file and exits. When the program loads, I want it to check the file for the existing username. If it finds the username, check the date on which it was recorded and if it was within 6 months exit the program. If it was recorded more than 6 months ago, run the program. Obviously, if the reading of the file doesn't find the username I want the program to run as well. Here is my code so far -
namespace EUSAA
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
txtDateTime.Text = DateTime.Now.ToString();
txtUsername.Text = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
btnClose.Visible = false;
chkAgree.Visible = true;
rtbSecurityAwareness.LoadFile("Security Awareness.rtf");
}
private void chkAgree_CheckedChanged(object sender, EventArgs e)
{
if (chkAgree.Checked)
{
btnClose.Visible = true;
}
else btnClose.Visible = false;
}
private void btnClose_Click(object sender, EventArgs e)
{
using (StreamWriter sw = File.AppendText(#"I:\Security Awareness Signed Users\Signed Users.txt"))
{
sw.WriteLine(System.Security.Principal.WindowsIdentity.GetCurrent().Name + "\t" + DateTime.Now.ToString());
}
Environment.Exit(0);
}
This isn't a code writing site; but I was feeling generous. The following class encapsulates storing and retrieving the latest agreement for the current user.
public class AgreementRepository
{
private const string FileLocation = #"I:\Security Awareness Signed Users\Signed Users.txt";
private const char Separator = '\t';
public void AppendAgreementForCurrentUser()
{
string currentUser = GetCurrentUser();
using (StreamWriter sw = File.AppendText(FileLocation))
{
sw.WriteLine($"{currentUser}{Separator}{DateTime.Now:O}");
}
}
public DateTime? GetLastAgreementForCurrentUser()
{
string currentUser = GetCurrentUser();
if (File.Exists(FileLocation) == false)
{
return null;
}
var lastAgreement = File.ReadLines(FileLocation)
.Select(x => x.Split(Separator))
.Where(x => x.Length == 2 && string.Equals(x[0], currentUser, StringComparison.CurrentCultureIgnoreCase))
.Select(x => GetDateTime(x[1]))
.Max();
return lastAgreement;
}
private static DateTime? GetDateTime(string input)
{
DateTime result;
if (DateTime.TryParse(input, out result))
{
return result;
}
return null;
}
private static string GetCurrentUser()
{
return System.Security.Principal.WindowsIdentity.GetCurrent().Name;
}
}
To use this, your form would become...
public partial class frmMain : Form
{
private readonly AgreementRepository _agreementRepository;
public frmMain()
{
_agreementRepository = new AgreementRepository();
InitializeComponent();
txtDateTime.Text = DateTime.Now.ToString();
txtUsername.Text = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
btnClose.Visible = false;
chkAgree.Visible = true;
rtbSecurityAwareness.LoadFile("Security Awareness.rtf");
this.Load += Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
var lastAgreement = _agreementRepository.GetLastAgreementForCurrentUser();
// NOTE: The following condition deals with the fact that lastAgreement could be null
if (lastAgreement > DateTime.Now.AddMonths(-6))
{
Close(); // or Environment.Exit; depends what you need
}
}
private void chkAgree_CheckedChanged(object sender, EventArgs e)
{
btnClose.Visible = chkAgree.Checked; // simplification of your posted code
}
private void btnClose_Click(object sender, EventArgs e)
{
_agreementRepository.AppendAgreementForCurrentUser();
Environment.Exit(0); // Would 'Close()' be enough?
}
Hope this helps
So, my issue here may turn out to be simple. I know how to create a method to callback from the application, but my issue is trying to figure out how to do it properly in this manner. I need to take the foreach loop that is repeated :(foreach (Ticket t in events)
{
if (t.getName().Equals(cbEvents.SelectedItem.ToString()))
{
)
and change it to a method to be called on twice in the code. Please help. Code below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TicketPurchasing
{
public partial class Form1 : Form
{
private ArrayList events;
public Form1()
{
InitializeComponent();
events = new ArrayList();
}
private void Form1_Load(object sender, EventArgs e)
{
//Create events
events.Add(new Game(12.00, "KSU vs UGA", "Convocation Building", "bball", "Basketball"));
events.Add(new Game(15.00, "KSU vs GSU", "Stadium", "fball", "Football"));
events.Add(new Concert(8.00, "Country Music", "Campus Green", "hayes", "Hunter Hayes"));
events.Add(new Concert(12.00, "Rock/Pop", "Campus Green", "m5", "Maroon5"));
//Load combobox
foreach (Ticket t in events)
{
cbEvents.Items.Add(t.getName());
}
}
private void btnDetails_Click(object sender, EventArgs e)
{
//Get name of selected item from combobox
string eventName;
//Traverse array to determine the match
foreach (Ticket t in events)
{
if (t.getName().Equals(cbEvents.SelectedItem.ToString()))
{
//Display details
lblDetails.Text = t.getDetails();
//Display image
displayImage(t.getFileName());
}
}
}
private void displayImage(string file)
{
Size size = new Size(173, 180);
Image img = (Image)Properties.Resources.ResourceManager.GetObject(file);
img = (Image)(new Bitmap(img, size));
pbImage.Image = img;
pbImage.Refresh();
pbImage.Visible = true;
}
private void txtTickets_TextChanged(object sender, EventArgs e)
{
//Get number of tickets
int num = int.Parse(txtTickets.Text);
double ticketCost = 0;
//Get cost of ticket
foreach (Ticket t in events)
{
if (t.getName().Equals(cbEvents.SelectedItem.ToString()))
{
ticketCost = t.getCost();
}
}
//Calculate cost
double total = num * ticketCost;
//Display cost
txtCost.Text = total.ToString("c");
}
private void btnExit_Click(object sender, EventArgs e)
{
//Exit the application
this.Close();
}
private void btnClear_Click(object sender, EventArgs e)
{
//Clear all information
lblDetails.Text = "";
pbImage.Image = null;
txtTickets.Text = "0";
txtCost.Text = "";
}
}
}
Are you trying to achieve something like this?
private void btnDetails_Click(object sender, EventArgs e)
{
//Get name of selected item from combobox
string eventName;
//Traverse array to determine the match
MethodAfterRefactor(() =>
{
//Display details
lblDetails.Text = t.getDetails();
//Display image
displayImage(t.getFileName());
});
}
private void MethodAfterRefactor(Func<object> p)
{
foreach (Ticket t in events)
{
if (t.getName().Equals(cbEvents.SelectedItem.ToString()))
{
p.Invoke();
}
}
}
Try thinking about this slightly differently, let's start by working out what you really want to do.
You have two lists, one represents the View artefacts cbEvents, the other the data behind that (sometimes known as the ViewModel) events.
What you are trying to do is match your ViewModel from your View because you only put the name into the view.
If you instead put your ViewModel into your View so that it can be rendered as just the name, then this code goes away. Something like
public class Ticket
{
...
public string override ToString() { return getName(); }
}
private void Form1_Load(object sender, EventArgs e)
{
...
//Load combobox
foreach (Ticket t in events)
{
cbEvents.Items.Add(t);
}
}
Then you can do stuff like
private void btnDetails_Click(object sender, EventArgs e)
{
Ticket t = cbEvents.SelectedItem as Ticket;
if (t !=null)
{
//Display details
lblDetails.Text = t.getDetails();
//Display image
displayImage(t.getFileName());
}
}
This is obviously a totally different way of thinking about this but is much easier. You may also find that some controls don't support binding to the object so well, in which case (at least in WinForms) you can use the Tag field
lblText.Text = t.getName();
lblText.Tag = t;
or in WPF the DataContext so you then bind to the fields e.g.
<TextBlock Text="{Binding Name}"/>
I am trying to write a text editor using RichTextBox. My concern is now about Undo and possibly Redo features of RichTextBox.
When I start writing in text box, say 1 minute! if I call Undo method, all it does is just I beleive clearing or resetting richtextbox again. How can I get it to work that it can do better, like Undoing last added word, or last added new line...I mean usual things you expect from Undo function. (The same counts for Redo also!)
Is there properties or some options to achive this? Or I have to implement my own code?
Just to go on from ahmadali's code - you can put it into a seperate class, and implement the redo functionality also:
NB. yes, it saves all the text every time the textbox is changed, so you can change that if your app will be used for massive amounts of text or if the app will be open for extended periods (ie days/weeks)
public partial class MainForm : Form
{
Undoer undoer;
public MainForm()
{
InitializeComponent();
this.txtBox.TextChanged += new EventHandler( TextBoxTextChanged );
this.undoer = new Undoer(ref this.txtText);
// create a context menu
ContextMenu menu = new ContextMenu();
menu.MenuItems.AddRange( new MenuItem[] {
new MenuItem("&Undo", new EventHandler( this.undoer.undo_Click )),
new MenuItem("&Redo", new EventHandler( this.undoer.redo_Click ))
});
this.txtBox.ContextMenu = menu;
// or create keypress event
this.txtBox.KeyDown += new KeyEventHandler( textBox_KeyDown );
this.KeyDown += new KeyEventHandler( textBox_KeyDown );
}
protected void TextBoxTextChanged(object sender, EventArgs e)
{
undoer.Save();
}
protected void textBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.Modifiers == (System.Windows.Forms.Keys.Control))
{
if ( e.KeyCode == Keys.Z )
{
this.undoer.Undo();
e.Handled = true;
}
if ( e.KeyCode == Keys.Y )
{
this.undoer.Redo();
e.Handled = true;
}
}
}
}
public class Undoer
{
protected System.Windows.Forms.RichTextBox txtBox;
protected List<string> LastData = new List<string>();
protected int undoCount = 0;
protected bool undoing = false;
protected bool redoing = false;
public Undoer(ref System.Windows.Forms.RichTextBox txtBox)
{
this.txtBox = txtBox;
LastData.Add(txtBox.Text);
}
public void undo_Click(object sender, EventArgs e)
{
this.Undo();
}
public void redo_Click(object sender, EventArgs e)
{
this.Redo();
}
public void Undo()
{
try
{
undoing = true;
++undoCount;
txtBox.Text = LastData[LastData.Count - undoCount - 1];
}
catch { }
finally{ this.undoing = false; }
}
public void Redo()
{
try
{
if (undoCount == 0)
return;
redoing = true;
--undoCount;
txtBox.Text = LastData[LastData.Count - undoCount - 1];
}
catch { }
finally{ this.redoing = false; }
}
public void Save()
{
if (undoing || redoing)
return;
if (LastData[LastData.Count - 1] == txtBox.Text)
return;
LastData.Add(txtBox.Text);
undoCount = 0;
}
}
You can save the lastest Data and when you want to undo you can change to now data to last data! lastest data can be set anytime that you want!
I Make a winForm with a richTextBox and a button that button undo the wrote text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace test
{
public partial class Form1 : Form
{
List<string> LastData = new List<string>();
int undoCount = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
LastData.Add(richTextBox1.Text);
}
private void button1_Click(object sender, EventArgs e)
{
try
{
richTextBox1.Text = LastData[LastData.Count - undoCount - 1];
++undoCount;
}
catch { }
}
private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
{
LastData.Add(richTextBox1.Text);
undoCount = 0;
}
}
}
but I didn't find any better and organized way and you can change
LastData.Add(richTextBox1.Text);
undoCount = 0;
to save new words or new line
update:
if you want to save the Ram you can delete the first data on list after many undo saving.