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.
Related
I am trying to auto check every new item in my checkedboxlist I have a button that does that it will auto select all, but we don't want it that way to be controlled by a button. we want it so for every new item we get automatically will get checked.
This is my button that auto select all if there are new 20 items this will auto select all and then submit those new items
Here is the code it works but is not I want I want to auto select for every new items coming in, because I have another process that will keep adding new items to the checkedboxlist, also the lst_BarcodeScanEvents is the checkedboxlist name
private void btn_SelectALLScans_Click(object sender, EventArgs e)
{
for (var i = 0; i < lst_BarcodeScanEvents.Items.Count; i++)
{
lst_BarcodeScanEvents.SetItemChecked(i, true);
}
}
I checked other sources like google and stackoverflow but I could not find anything to my request here.
Here is the main class where I have the logic of buttons, checkedlistbox and more. and the button method btn_ConnectT_Click calls the methods from the second class
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Web;
using BarcodeReceivingApp.Core.Domain;
using BarcodeReceivingApp.Functionality;
namespace BarcodeReceivingApp
{
public partial class BarcodeReceivingForm : Form
{
//GLOBAL VARIABLES
private const string Hostname = "myip";
private const int Port = 23;
private TelnetConnection _connection;
private ParseReceivingBarcode _parseReceivingBarcode;
private ButtonsDisplay _buttonsDisplay;
public BarcodeReceivingForm()
{
InitializeComponent();
//FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
}
private void btn_ConnectT_Click(object sender, EventArgs e)
{
_connection = new TelnetConnection(Hostname, Port);
_connection.ServerSocket(Hostname, Port, this);
}
private void btn_StopConnection_Click(object sender, EventArgs e)
{
_connection.Exit();
}
private void btn_RemoveItemFromListAt_Click(object sender, EventArgs e)
{
if (lst_BarcodeScanEvents.CheckedItems.Count != 0)
for (var i = lst_BarcodeScanEvents.CheckedItems.Count; i > 0; i--)
lst_BarcodeScanEvents.Items.RemoveAt(lst_BarcodeScanEvents.CheckedIndices[i - 1]);
else
MessageBox.Show(#"Element(s) Not Selected...");
}
private void BarcodeReceivingForm_Load(object sender, EventArgs e)
{
_buttonsDisplay = new ButtonsDisplay(this);
_buttonsDisplay.ButtonDisplay();
}
private void btn_ApplicationSettings_Click(object sender, EventArgs e)
{
var bcSettingsForm = new BarcodeReceivingSettingsForm();
bcSettingsForm.Show();
}
private void btn_ClearBarcodeList_Click(object sender, EventArgs e)
{
lst_BarcodeScanEvents.Items.Clear();
}
private void lst_BarcodeScanEvents_ItemAdded(object sender, ListBoxItemEventArgs e)
{
MessageBox.Show(#"Item was added at index " + e.Index + #" and the value is " + lst_BarcodeScanEvents.Items[e.Index].ToString());
}
private void btn_SubmitData_Click(object sender, EventArgs e)
{
var receivingFullBarcode = new List<string>();
_connection.GetBarcodeList();
}
private void btn_SelectALLScans_Click(object sender, EventArgs e)
{
for (var i = 0; i < lst_BarcodeScanEvents.Items.Count; i++)
{
lst_BarcodeScanEvents.SetItemChecked(i, true);
}
}
}
}
Here is the second class where I use a telnet port 23 that scan barcodes where and puts it to the checkedlistbox, now the main emethods here that inserts the data to the checkedlistbox is the method serversocket and the readwrite method
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace BarcodeReceivingApp.Functionality
{
public class TelnetConnection
{
private Thread _readWriteThread;
private TcpClient _client;
private NetworkStream _networkStream;
private string _hostname;
private int _port;
private BarcodeReceivingForm _form;
private bool _isExiting = false;
public TelnetConnection(string hostname, int port)
{
this._hostname = hostname;
this._port = port;
}
public void ServerSocket(string ip, int port, BarcodeReceivingForm f)
{
this._form = f;
try
{
_client = new TcpClient(ip, port);
}
catch (SocketException)
{
MessageBox.Show(#"Failed to connect to server");
return;
}
_networkStream = _client.GetStream();
_readWriteThread = new Thread(ReadWrite);
//_readWriteThread = new Thread(() => ReadWrite(f));
_readWriteThread.Start();
}
public void Exit()
{
_isExiting = true;
}
public void ReadWrite()
{
do
{
var received = Read();
if (received == null)
break;
if (_form.lst_BarcodeScanEvents.InvokeRequired)
{
var received1 = received;
_form.lst_BarcodeScanEvents.Invoke(new MethodInvoker(delegate
{
_form.lst_BarcodeScanEvents.AddItem(received1 + Environment.NewLine);
}));
}
} while (!_isExiting);
//var material = received.Substring(10, 5);
//_form.label5.Text += string.Join(Environment.NewLine, material);
CloseConnection();
}
public List<string> GetBarcodeList()
{
var readData = new List<string>();
foreach (string list in _form.lst_BarcodeScanEvents.Items)
{
readData.Add(list);
MessageBox.Show(list);
}
return readData;
}
public string Read()
{
var data = new byte[1024];
var received = "";
var size = _networkStream.Read(data, 0, data.Length);
if (size == 0)
return null;
received = Encoding.ASCII.GetString(data, 0, size);
return received;
}
public void CloseConnection()
{
MessageBox.Show(#"Closed Connection",#"Important Message");
_networkStream.Close();
_client.Close();
}
}
}
so now like I said before for every new items it gets inserted to the checkedlistbox I want it to be auto selected everytime it adds a new data to the checkedlistbox.
The problem, usually simple, of setting the Checked state of a newly added Item of a CheckedListBox, was somewhat complicated because of the nature of the Listbox in question.
The CheckedListBox is a Custom Control with custom events and properties.
It's actually a relatively common customization (one implementation can be see in this MSDN Forum post:
Have ListBox an event when addid or removing Items?) but it might complicate the interpretation of the events.
The Custom Control, when adding a new Item to the List (from a class other than the Form that hosts the Control), raises the custom ItemAdded event
private void [CheckedListBox]_ItemAdded(object sender, ListBoxItemEventArgs e)
The Index of the Item added is referenced by the e.Index property of the custom ListBoxItemEventArgs object.
With the code provided, it can be determined that this event handler is the natural place where the Checked state of the new Item can be set:
private void lst_BarcodeScanEvents_ItemAdded(object sender, ListBoxItemEventArgs e)
{
lst_BarcodeScanEvents.SetItemChecked(e.Index, true);
}
For that I suggest to create an event that you subscribe after you InitializeComponent() of your form like so :
public Form1()
{
InitializeComponent();
lst_BarcodeScanEvents.ControlAdded += new ControlEventHandler(AddedNewSelect);
}
private void AddedNewSelect(object sender, ControlEventArgs e)
{
lst_BarcodeScanEvents.SetItemChecked(e.Control.TabIndex, true);
}
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.
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.
I am displaying all of the worlds countries in a combobox called countrybox.
A second combobox contains all of the cities in a country called citybox.
When you choose a country, citybox appears and when you open countrybox, citybox dissapears again.
The problem arises when you open citybox and click outside of it.
citybox dissapears when you
open countrybox and does not come back when you click outside of countrybox.
I tried with this:
string ctext { get; set; }
private void countrybox_SelectedIndexChanged(object sender, EventArgs e)
{
citybox.Visible = true;
string ctext = countrybox.Text;
}
private void countrybox_DropDownClosed(object sender, EventArgs e)
{
if (countrybox.Text == ctext)
{
citybox.Visible = true;
}
else
{
citybox.Visible = false;
}
However, this did not work as i wanted it to.
Im guessing it is because the Combobox class does not recognize a click outside of the box as a _DropDownClosed event.
I have also tried with using the
validating event to check if a user clicks on the form
private void countrybox_Validating(object sender, CancelEventArgs e)
{
if (string.Equals((sender as Form).Name, #"Form1") && string.IsNullOrEmpty(countrybox.Text))
{
e.Cancel = true;
MessageBox.Show("You have to select a country!");
}
}
Is there anyway to make the combobox dropdownlist to not close when clicked outside of the list?
I apologize if i have any Spelling misstakes, my native language is not English.
Posting my full code below for people who want more details.
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;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string[] Countries = File.ReadAllLines(#"C:\Travelbureau\Countries.txt");
Array.Sort(Countries);
for (int i = 0; i < Countries.Length; i++)
{
countrybox.Items.Add(Countries[i]);
}
}
string ctext { get; set; }
private void countrybox_SelectedIndexChanged(object sender, EventArgs e)
{
citybox.Visible = true;
string ctext = countrybox.Text;
switch (countrybox.Text)
{
case "Afghanistan":
string[] AfgCity = File.ReadAllLines(#"C:\Travelbureau\Afghanistan.txt");
Array.Sort(AfgCity);
for (int i = 0; i < AfgCity.Length; i++)
{
citybox.Items.Add(AfgCity[i]);
}
break;
default:
citybox.Text = "City";
citybox.Items.Clear();
break;
}
}
private void countrybox_DropDown(object sender, EventArgs e)
{
citybox.Visible = false;
}
private void countrybox_DropDownClosed(object sender, EventArgs e)
{
if (countrybox.Text == ctext)
{
citybox.Visible = true;
}
else
{
citybox.Visible = false;
}
private void countrybox_Click(object sender, EventArgs e)
{
countrybox.Text = "";
citybox.Visible = false;
}
private void citybox_Click(object sender, EventArgs e)
{
citybox.Text = "";
}
private void countrybox_Validating(object sender, CancelEventArgs e)
{
if (string.Equals((sender as Form).Name, #"Form1") && string.IsNullOrEmpty(countrybox.Text))
{
e.Cancel = true;
MessageBox.Show("You have to select a country!");
}
}
}
}
It's been a while since I did anything with Windows Forms, but you should be able to accomplish this with the Validating event. If you check in that to see whether it has a value and set e.Cancel accordingly, I believe that will give you your desired behavior.
In my experience, it's a very good idea to set some sort of status visible to the user in that event, though. It can be confusing when a user is no longer able to click anywhere. You can do that with a MessageBox or a Label. But that's really a UX matter that isn't directly relevant to your question.
You might also have to set a property that indicates that it should validate when you leave the control, but I don't believe that's the case. If someone knows for sure I'll update this answer to reflect that.
And yes, you can change the visibility of cityBox in that method as well.
In visual studio I have a program that currently takes 5 pictures everytime you click the button. I want the program to take those 5 pictures then change the Aperture setting and take 1 last picture.
There isn't really relevant code, so this is for someone who already understands the SDK.
I've already looked around quite a bit for how to handle this, but I'm rather inexperienced with coding in general.
Thanks!
maybe useful code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using EDSDKLib;
using CanonCameraAppLib;
using CanonCameraAppLib.Remote;
namespace CanonCameraApp
{
public partial class CanonCameraApp : Form
{
public delegate void TakePhotoDelegate(int delay);
private CameraAPI api;
private RemoteServer server;
private TakePhotoDelegate takePhotoDelegate;
public CanonCameraApp()
{
InitializeComponent();
api = CameraAPI.Instance;
takePhotoDelegate = new TakePhotoDelegate(takePhotograph);
init();
}
private void server_OnTakePhotoCommandEvent(RemoteCommandEventArgs e)
{
this.Invoke(takePhotoDelegate, e.Delay);
}
private void init()
{
loadCameras();
registerEvents();
if (Convert.ToBoolean(ConfigurationManager.AppSettings["StartServerOnStartup"]))
{
startServerListener();
}
}
private void registerEvents()
{
CameraAPI.OnCameraAdded += new CameraAddedEventHandler(api_OnCameraAdded);
}
private void api_OnCameraAdded(CameraAddedEventArgs e)
{
scanForCamerasToolStripMenuItem_Click(null, new EventArgs());
}
private void startServerListener()
{
server = new RemoteServer(Convert.ToInt32(ConfigurationManager.AppSettings["ListenPort"]));
server.OnTakePhotoCommandEvent += new TakePhoto(server_OnTakePhotoCommandEvent);
new Thread(server.Start).Start();
}
private void loadCameras()
{
try
{
cbCameras.DataSource = api.Cameras;
cbCameras.DisplayMember = "Name";
cbCameras.Enabled = true;
btnTakePhoto.Enabled = true;
btnProperties.Enabled = true;
scanForCamerasToolStripMenuItem.Enabled = false;
subscribeToEvents();
}
catch (CameraNotFoundException)
{
MessageBox.Show("No cameras were detected. Please make sure that they are plugged in and are turned on.");
cbCameras.Enabled = false;
btnTakePhoto.Enabled = false;
btnProperties.Enabled = false;
scanForCamerasToolStripMenuItem.Enabled = true;
}
}
private void subscribeToEvents()
{
List<Camera> cameras = getCameraList();
foreach (Camera camera in cameras)
{
camera.OnNewItemCreated += new CanonCameraAppLib.Events.NewItemCreatedEventHandler(camera_OnNewItemCreated);
}
}
void camera_OnNewItemCreated(Camera sender, CanonCameraAppLib.Events.NewItemCreatedEventArgs e)
{
if (chbPreview.Checked)
{
PhotoPreview preview = new PhotoPreview(e.Item, true);
preview.Show();
}
}
// private void changeAperature(int value)
//{
// Camera camera = getSelectedCamera();
// camera.changeAperture(value);
//}
private void takePhotograph(int delay)
{
Camera camera = getSelectedCamera();
camera.takePhotograph(delay);
}
private Camera getSelectedCamera()
{
return (Camera)cbCameras.SelectedItem;
}
private List<Camera> getCameraList()
{
List<Camera> cameras = new List<Camera>(cbCameras.Items.Count);
foreach (object camera in cbCameras.Items)
{
cameras.Add((Camera)camera);
}
return cameras;
}
#region Handled Form Events
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i <=4; i++)
takePhotograph(Convert.ToInt16(textBox1.Text));
for (int i = 0; i <= 1; i++)
;
}
private void scanForCamerasToolStripMenuItem_Click(object sender, EventArgs e)
{
loadCameras();
}
private void quitToolStripMenuItem_Click(object sender, EventArgs e)
{
quit();
}
private void CanonCameraApp_FormClosing(object sender, FormClosingEventArgs e)
{
quit();
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
new About().ShowDialog(this);
}
/// <summary>
/// Opens the Camera Properties window
/// </summary>
private void btnProperties_Click(object sender, EventArgs e)
{
new CameraProperties(getSelectedCamera()).Show();
}
#endregion
private void quit()
{
if (server != null)
{
server.Stop();
}
Application.ExitThread();
Application.Exit();
}
}
}
This is what the application it self looks like. There are several dll's and other things involved.