This application is a message board type of app. You post a message, which is stored in an Oracle database. The user's photo, name, date and message are displayed in a listview. Everything works however a feature request for font color changing came in. Now testing things below I know I can display ALL of the messages as a certain color.
What I'm going to do is add a 'color' column to my table. Then if a user selects the text of their message to be 'red' for example, I am going to store the hex color for red in the color column of the table for that post.
So what I'm trying to figure out is when that message is retrieved, how I can set this code to 'If color column empty, post message as black, else if hex color exist for each message post that particular message in that color' Without changing the color of every message to red as the code below currently does.
List<MsgBoard> Messages = MsgBoard.find_ActiveByBoardName(Convert.ToString(cmbgroup.SelectedItem));
int i = 0;
imageList1.Images.Clear();
foreach (MsgBoard m in Messages)
{
AddImages(m.EmpPic);
ListViewItem Message = new ListViewItem("", i);
if (m.AlertNo == 0) //Default Message Post (non Alert)
{
Message.UseItemStyleForSubItems = false;
Message.SubItems.Add(m.EmpName.First);
Message.SubItems.Add(m.MessageText + Environment.NewLine).ForeColor = Color.Red;
Message.SubItems.Add(m.PostDate.ToString());
Message.SubItems.Add(m.EmpName.EmpNo.ToString());
Message.SubItems.Add(m.EmpName.Name);
listView1.Items.Add(Message);
}
i++;
}
}
Just to clarify. If 20 people post a message and all 20 select a different color to post their message in. So in the DB all 20 rows have a different color in the DB column, I need to have those messages displayed in listview individually based on the color they posted as. I currently am only aware of applying a single color to all messages in listview as shown in my example above.
Looks like thanks to Stephan, once I add
Message.SubItems.Add(m.MessageText + Environment.NewLine).ForeColor = System.Drawing.ColorTranslator.FromHtml(m.Color);
I then need help adjusting my query to add the color once colors are added to the color column. Here is that code.
Had DB admin add MESSAGE_COLOR varchar column.
I edit this below to existing code, for the newly created column MESSAGE_COLOR when posting..
public string Create()
{
try
{
OleDbDataReader result = Database.Conn.Execute(
"INSERT INTO MPCS.MEYER_BOARD (" +
"EMPLOYEE_ID, " +
"POST_DATE, " +
"BOARD_NAME," +
"ALERT_NO," +
"MESSAGE_TEXT," +
"MESSAGE_COLOR," +
"ACTIVE_FLAG" +
") VALUES (?,SYSDATE,?,?,?,?)",
new List<OleDbParameter> {
new OleDbParameter("EMPLOYEE_ID",EmpName.EmpNo),
new OleDbParameter("BOARD_NAME",BoardName),
new OleDbParameter("ALERT_NO",AlertNo),
new OleDbParameter("MESSAGE_TEXT",MessageText),
new OleDbParameter("MESSAGE_COLOR",MessageColor),
new OleDbParameter("ACTIVE_FLAG",ActiveFlag ? "Y" : "N")
}, Query.ReaderType.Reader);
result.Read();
result.Close();
return null;
}
catch (Exception ex)
{
return ex.Message;
}
}
I then editing DB read w/ the new column as well.
public static MsgBoard DBRead(OleDbDataReader result,string alias=null)
{
return new MsgBoard
{
EmpName = Employee.DBRead(result, "EMPLOYEE"),
MessageText = result[alias + "MESSAGE_TEXT"].ToString(),
MessageColor = result[alias + "MESSAGE_COLOR"].ToString(),
BoardName = result[alias +"BOARD_NAME"].ToString(),
AlertNo = (int)(decimal)result[alias +"ALERT_NO"],
PostDate = (DateTime)result[alias +"POST_DATE"],
ActiveFlag = result[alias +"ACTIVE_FLAG"].ToString().ToString() == "Y",
EmpPic = ImageResource.DBRead(result, "IR")
};
}
But do I need to edit my build_query?
public static String build_query(String where, string OrderBy = null)
{
List<String> cols = new List<String>();
cols.AddRange(db_columns.ConvertAll(c => "MPCS.MEYER_BOARD." + c + " AS MBOARD_" + c));
cols.AddRange(Employee.db_columns.ConvertAll(c => "MPCS.EMPLOYEE." + c + " AS EMPLOYEE_" + c));
cols.AddRange(ImageResource.db_columns.ConvertAll(c => "MPCS.IMAGE_RESOURCE." + c + " AS IR_" + c));
String sql =
"SELECT " + String.Join(", ", cols) + " " +
"FROM MPCS.MEYER_BOARD " +
"LEFT OUTER JOIN MPCS.EMPLOYEE " +
"ON MPCS.MEYER_BOARD.EMPLOYEE_ID=MPCS.EMPLOYEE.EMPLOYEE_ID " +
"LEFT OUTER JOIN MPCS.IMAGE_RESOURCE " +
"ON MPCS.IMAGE_RESOURCE.IR_ID=MPCS.EMPLOYEE.IMAGE_RESOURCE_ID " +
"WHERE ";
sql += where;
sql += OrderBy;
return sql;
}
UPDATE
I've gotten everything coded and I am submitting the color to the DB now. However when displaying the listview below each post still just has a default black text color. Rather than the color saved for example as "#FFF000" being converted and displayed.
foreach (MsgBoard m in Messages)
{
AddImages(m.EmpPic);
ListViewItem Message = new ListViewItem("", i);
if (m.AlertNo == 0) //Default Message Post (non Alert)
{
Message.SubItems.Add(m.EmpName.First);
Message.SubItems.Add(m.MessageText + Environment.NewLine).ForeColor = System.Drawing.ColorTranslator.FromHtml(m.MessageColor);
Message.SubItems.Add(m.PostDate.ToString());
Message.SubItems.Add(m.EmpName.EmpNo.ToString());
Message.SubItems.Add(m.EmpName.Name); //Displayed only on 'Show Details'
listView1.Items.Add(Message);
}
Final update
Turns out the last piece I was missing was to change the listview property UseItemStyleForSubItems = false; now its working.
You can convert your hex value (assuming that it is stored as a string in the format "#RRGGBB") into a color using ColorTranslator
Using this approach, you can also use named colors (like "Violet")
Message.SubItems.Add(m.MessageText + Environment.NewLine).ForeColor =
System.Drawing.ColorTranslator.FromHtml(m.Color); //sth. like "#FFCC66"
Furthermore you have to retrieve the value of the Color column. It seems that you have to add "MESSAGE_COLOR" (or whatever your column is called) to your db_columns. When you got the values from the DB, you have to map the column to the property of your Message:
return new MsgBoard
{
// ...
Color = System.Drawing.ColorTranslator.FromHtml([alias+"MESSAGE_COLOR"]),
// ...
}
(In other words: You already save it to db, now you also have to read it from DB)
Related
I'm a C# newbie_and in programming in general_ and in a previous question C# return linq result as a list from a wcf service method then use it in aspx web forms page , I managed to return a row from a table and display the result in labels in my apx web forms page. Now I want to display the whole table-> an unknown number of rows. I edited my code and I was almost successful. The problem is that the table that I get, instead of the four different rows that my table contains, displays the first one four times. I check again and again but I can't find the error nor some friends. Here is my code:
staffPanel.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
displayClients_Ref.IdisplayClientsSrvcClient dcClient = new displayClients_Ref.IdisplayClientsSrvcClient();
List<string> allClients = new List<string>(dcClient.displayClients());
foreach (string row in allClients)
{
int size = 0;
string client = allClients.FirstOrDefault();
if (String.IsNullOrEmpty(client))
{
// record cannot be found
}
else
{
string[] columns = client.Split(';');
size = columns.Length;
TableRow tr = new TableRow();
allClients_tbl.Rows.Add(tr);
for (int i = 0; i < size; i++)
{
TableCell tc = new TableCell();
tc.Text = columns[i];
tr.Cells.Add(tc);
}
}
}
}
displayClient.svc.cs
public List<string> displayClients()
{
List<string> result = new List<string>();
try
{
using (paragon_db_Models.clients_Entity context = new paragon_db_Models.clients_Entity())
{
var query = from cl in context.clients
select cl;
foreach (var c in query)
{
string row = c.user_account_id + ";" + c.client_name + ";" + c.client_surname + ";" + c.business_name + ";" + c.client_address + ";" + c.postal_code + ";" + c.telephone_number + ";" + c.fax + ";" + c.email + ";" + c.fiscal_code + ";" + c.public_fiscal_service;
result.Add(row);
}
}
return result;
}
catch (Exception)
{
return result;
}
}
If it is a simple, stupid little mistake that I cannot see I will remove the question. I'm open to suggestions and comments concerning a different way of doing this.
You don't need
string client = allClients.FirstOrDefault();
You are already getting the info you want with "row" in
foreach (string row in allClients)
Replace your "client" instances with "row". FirstOrDefault would always get the first object or null.
I'm trying to replicate a log window, so the most recent log should appear at the top - most visible. Thus, I need to add a text to the top (no problem) but with multiple colors (problem).
First I store the original text. (it's rtf or text - tried both)
And then I add the new text, with a username and then a message. The username should be one color and the message another. It's always single lined too.
All I get by my method is that when appending the old text or the old RTF text, the latest "log" only shows.
public void AddLog(Log log)
{
try
{
string oldText = this.richTextBox1.Rtf;
this.richTextBox1.Text = log.User + ": " + log.Message + "\n";
this.richTextBox1.Select(0, log.User.Length);
this.richTextBox1.SelectionColor = Color.GreenYellow;
this.richTextBox1.Select(log.User.Length + 2, log.Message.Length);
this.richTextBox1.SelectionColor = Color.White;
this.richTextBox1.DeselectAll();
this.richTextBox1.Rtf += oldText;
}
catch { }
}
Is this even possible? Because it doesn't save the old RTF text and the old RTF text can't be appended after the new text, which means I probably have to add newest text below which isn't what I want.
If I instead of saving the "RTF" text, the format (colors) will disappear and will only show one color.
Not tested but try this
public void AddLog(Log log)
{
try
{
richTextBox1.SelectAll();
string oldText = this.richTextBox1.SelectedRtf;
this.richTextBox1.Text = log.User + ": " + log.Message + "\n";
this.richTextBox1.Select(0, log.User.Length);
this.richTextBox1.SelectionColor = Color.GreenYellow;
this.richTextBox1.Select(log.User.Length + 2, log.Message.Length);
this.richTextBox1.SelectionColor = Color.White;
this.richTextBox1.DeselectAll();
this.richTextBox1.SelectionStart = this.richTextBox1.TextLength;
this.richTextBox1.SelectedRtf = oldText;
this.richTextBox1.DeselectAll();
}
catch { }
}
I have a C# WinForms application that has four chart controls used to graphically show some analysis results.
I have the code working for each graph, however in an attempt to be more efficient & re-use code I've defined a code block to:
create the required series,
extracts the data from a database & assigns the results to the appropriate series
add the series to the chart
customise the charts appearance.
All of the above is done dynamically as the data does not exist at design time.
The working code I am looking to re-use is:
// Add both series to the chart.
ChartName.Series.AddRange(new Series[] { series1, series2 });
// Cast the chart's diagram to the XYDiagram type, to access its axes.
XYDiagram diagram = (XYDiagram)ChartName.Diagram;
I'd like to change the ChartName object to a variable that I can pass each of the charts in order to re-use the code. Something like (note this does not work):-
var VChart = this.Controls.Find(ChartName, true);
// Add both series to the chart.
VChart.Series.AddRange(new Series[] { series1, series2 });
// Cast the chart's diagram to the XYDiagram type, to access its axes.
XYDiagram diagram = (XYDiagram)VChart.Diagram;
Any ideas, hints, tips, etc on how-to pass a variable into the ChartName would be appreciated.
Full Code:
void Generate_Chart()
{
// Create two stacked bar series.
Series series1 = new Series("Data", ViewType.Bar);
Series series2 = new Series("Ben", ViewType.Line);
try
{
using (var cmd = new SQLiteCommand(m_dbConnection))
for (int i = LoopMin; i < LoopMax; i++)
{
// Retrieve the actual calculated values from the database
cmd.CommandText = "SELECT " + Chart_SourceActualValue + " FROM " + Chart_SourceTable + " WHERE Value = " + i + "";
Chart_SeriesA_Value = Convert.ToInt32(cmd.ExecuteScalar());
// Retrieve the expected values from the database
cmd.CommandText = "SELECT " + Chart_BenExpValue + " FROM " + Chart_SourceTable + " WHERE Value = " + i + "";
Chart_SeriesB_Value = Convert.ToInt32(cmd.ExecuteScalar());
// Add the dynamically created values to a series point for the chart
series1.Points.Add(new SeriesPoint(i, Chart_SeriesA_Value));
series2.Points.Add(new SeriesPoint(i, Chart_SeriesB_Value));
}
}
catch (Exception)
{
throw;
}
// Add both series to the chart.
//this.Controls.Find(varChart, true)
ChartName.Series.AddRange(new Series[] { series1, series2 });
// Remove the GridLines from the chart for better UI
// Cast the chart's diagram to the XYDiagram type, to access its axes.
XYDiagram diagram = (XYDiagram)ChartName.Diagram;
// Customize the appearance of the axes' grid lines.
diagram.AxisX.GridLines.Visible = false;
}
}
It sounds like you're asking to replace the hardcoded ChartName with a variable so that you can call your routine four different times, each time with a different chart. I've taken your code and replaced some of the global variable of your chart control and settings and and made them parameters you pass into the function:
void Generate_Chart(DevExpress.XtraCharts.ChartControl chartCtrl,
string chart_sourceActualValue,
string chart_sourceTable,
string chart_benExpValue
)
{
// Create two stacked bar series.
Series series1 = new Series("Data", ViewType.Bar);
Series series2 = new Series("Ben", ViewType.Line);
try
{
using (var cmd = new SQLiteCommand(m_dbConnection))
for (int i = LoopMin; i < LoopMax; i++)
{
// Retrieve the actual calculated values from the database
cmd.CommandText = "SELECT " + sourceActualValue + " FROM " +
chart_sourceTable + " WHERE Value = " + i + "";
Chart_SeriesA_Value = Convert.ToInt32(cmd.ExecuteScalar());
// Retrieve the expected values from the database
cmd.CommandText = "SELECT " + chart_benExpValue + " FROM " +
chart_sourceTable + " WHERE Value = " + i + "";
Chart_SeriesB_Value = Convert.ToInt32(cmd.ExecuteScalar());
// Add the dynamically created values
// to a series point for the chart
series1.Points.Add(new SeriesPoint(i, Chart_SeriesA_Value));
series2.Points.Add(new SeriesPoint(i, Chart_SeriesB_Value));
}
}
catch (Exception)
{
throw;
}
// Add both series to the chart.
chartCtrl.Series.AddRange(new Series[] { series1, series2 });
// Remove the GridLines from the chart for better UI
// Cast the chart's diagram to the XYDiagram type, to access its axes.
XYDiagram diagram = (XYDiagram)chartCtrl.Diagram;
// Customize the appearance of the axes' grid lines.
diagram.AxisX.GridLines.Visible = false;
}
}
Then, you end up calling this method like this using the original values as arguments:
void Generate_Chart(ChartName, Chart_SourceActualValue, Chart_SourceTable,
Chart_BenExpValue);
// call it three other times passing in the different specifics for that chart. e.g.
void Generate_Chart(SomeOtherChartName, SomeOtherChart_SourceActualValue,
SomeOhterChart_SourceTable, SomeOtherChart_BenExpValue);
.....
I would like to click on an item in a listbox and display the attributes that were passed into that listbox to a multiline textbox.
Below is the code I have written on form initialisation
public Form1()
{
InitializeComponent();
ReadFromFile.Read("sample.GED");
foreach (KeyValuePair<int, Individual> kvp in ReadFromFile.individuals)
{
listBox2.Items.Add("ID = " + kvp.Value.id + " Name = " + kvp.Value.name.givenName + " " + kvp.Value.name.surname + " DoB = " + kvp.Value.birth.date);
}
int testIndividual = 94;
string genderOut = "";
if (ReadFromFile.individuals[testIndividual].gender == "M")
{
genderOut = "MALE";
}
else if (ReadFromFile.individuals[testIndividual].gender == "F")
{
genderOut = "FEMALE";
}
try
{
textBox1.AppendText(
"Name = " + ReadFromFile.individuals[testIndividual].name.givenName + " "
+ ReadFromFile.individuals[testIndividual].name.surname
+ Environment.NewLine + "Gender = " + genderOut
+ Environment.NewLine + "Birth date = " + ReadFromFile.individuals[testIndividual].birth.date
+ Environment.NewLine + "Birth place = " + ReadFromFile.individuals[testIndividual].birth.place
+ Environment.NewLine + "Death date = " + ReadFromFile.individuals[testIndividual].death.date
+ Environment.NewLine + "Death place = " + ReadFromFile.individuals[testIndividual].death.place);
}
catch
{
MessageBox.Show("This individual doesnt exist");
}
}
}
I would like to add more so I can click on a listbox item and the details for that item will be shown in the textbox
I get the feeling I may have to override the ToString() method or regex it. Im still quite a novice programmer so go easy on me :) THANK YOU
You need to handle the SelectedIndexChanged event for your listbox.
One way to do this is to bring up Form1.cs[Design] and select the listbox. In the property grid (Alt+Enter) click the icon that looks like this:
Find the event SelectedIndexChanged and double click it. That will hook up an event handler for you in the auto generated Form1.cs.designer file.
Next, replace the code for your Form1 class with the following:
public partial class Form1 : Form
{
private Dictionary<int, Individual> _individuals;
public Form1()
{
InitializeComponent();
ReadFromFile.Read("sample.GED");
_individuals = ReadFromFile.individuals;
listBox1.DataSource = _individuals.Select(individual => individual.Value).ToList();
listBox1.DisplayMember = "name";
listBox1.ValueMember = "id";
}
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.Clear();
var individual = listBox1.SelectedItem as Individual;
string genderOut = (individual.Gender == "M") ? "MALE" : "FEMALE";
var displayText
= String.Format("Name = {0} {1}\r\n" +
"Gender = {2}\r\n" +
"Birth date = {3}\r\n" +
"Birth place = {4}\r\n" +
"Death date = {5}\r\n" +
"Death place = {6}"
, individual.name.givenName
, individual.name.surname
, genderOut
, individual.birth.date
, individual.birth.place
, individual.death.date
, individual.death.place);
textBox1.AppendText(displayText);
}
}
A few notes about some of the things i've changed.
I've moved the code that was setting the textbox value into the SelectedIndexChanged event handler
I've refactored that code so that it's more readable by using the static String.Format method (all those Environment.NewLine repeats you had were messy).
I've setup the data for the list box using the DataSource property instead of your foreach loop.
Also, one thing you'll notice with this is that the list items in the listbox will not show the correct text. This is because you appear to be using some custom classes or structs for the name, birth and death of an Individual? To fix this, you need to add a new property to the Individual class like this:
public class Individual
{
// ... your code
public string DisplayName
{
get { return String.Format("{0} {1}), name.givenName, name.surname; }
}
// ... the rest of your code
}
Then you will need to change the line in my code above that looks like this:
listBox1.DisplayMember = "name";
to this:
listBox1.DisplayMember = "DisplayName";
Final note: You should probably be using "Upper Camel Case" for your property names. That means that they start with an upper case letter and then the first letter of each word is also upper case. For example, name.givenName should be Name.GivenName. This is a widely used convention.
I'm adding in two new fields into an already existing Sharepoint list programmatically through a feature. The fields are being added successfully but I have been unable to adjust the column order.
This task is done simply through the UI by going to List Settings and then Column Ordering, but I have been unable to achieve the task programmatically.
Through some research I've seen that you can use the SPContentType of the form to change the ordering of the FieldLinks (as follows):
SPList list = web.Lists["Example List"];
if (list.ContentTypes.Count > 0) {
SPContentType ct = list.ContentTypes[0];
string[] names = {"Example_x0020_One", "Example_x0020_Two", "Example_x0020_Three"};
ct.FieldLinks.Reorder(names);
ct.Update();
}
In this example, I the list would already have "Example One" and "Example Three" columns, and I would add "Example Two" later and then try to order them.
However this approach did not work for me, so if anyone has input on it, that would be appreciated.
The next item I saw is manually changing the SchemaXml of the list to have the proper order of the fields, but I wanted to see if this was the best method.
Any input would be appreciated, thank you for your help.
I took a look at the source of the Column ordering page (formEdt.aspx), it looks like they use web services, not the object model:
function DoBuildAndSubmit()
{
var numFound, currentSelect, selectValue;
var form = document.forms.aspnetForm;
var numFields = form["numSelects"].value;
var xml = "<Fields>";
numFound = 0;
while(numFound < numFields)
{
for(x = 0; x < numFields; x++)
{
currentSelect = form["FormPosition" + x];
if(currentSelect.selectedIndex == numFound)
{
selectValue = currentSelect.options[numFound].value;
xml = xml + "<Field Name=\"" + selectValue + "\"/>" + "\n";
numFound++;
}
}
}
for(x = numFields ; x < 67; x++)
xml = xml + "<Field Name=\"" + form["FormPosition" + x].value + "\"/>" + "\n";
xml = xml + "</Fields>";
document.frmLayoutSubmit["ReorderedFields"].value=xml;
document.frmLayoutSubmit.action = "http://local/_vti_bin/owssvr.dll?CS=65001";
document.frmLayoutSubmit.submit();
}
Now, it might be possible to do through the object model, but I don't have a good feeling about it when the UI is punting.
Here's a powershell version:
# Moves "FieldToBeMoved" after "Description" field
$list = $web.Lists["Documents"]
$ct = $list.ContentTypes[0] # Or find the desired CT
$newOrder = #()
foreach ($field in $ct.Fields)
{
if ($field.StaticName -ne "FieldToBeMoved")
{
$newOrder += $field.StaticName
}
if ($field.StaticName -eq "Description")
{
$newOrder += "FieldToBeMoved"
}
}
$ct.FieldLinks.Reorder($newOrder)
$ct.Update();
I used the code from your answer, except I programmatically examined the content types and fields for the list I wanted to re-order.
//Step 1 (optional): List out the content types and fields for your list to see what is in the list
SPList list = web.Lists[strListName];
string strRet="";
foreach (SPContentType spct in list.ContentTypes)
{
strRet += "<strong>Content Type: </strong>" + spct.Name + ", <strong>Fields</strong>: <br />";
foreach (SPField field in spct.Fields)
{
if (strFieldInfo != "")
{
strFieldInfo += ", ";
}
strFieldInfo += "\"" + field.StaticName + "\"";
}
strRet += strFieldInfo + "<br />-----<br />";
}
//Output the results
lblOutput.Text = strRet;
Now, you'll have an idea of how many content types your list has and what fields are in the list.
By default, if content type management is not enabled, you'll have one content type that has all the fields.
Sample output from the above code:
Content Type: Event, Fields:
"ContentType", "Title", "Location", "EventDate", "EndDate", "Description", "fAllDayEvent", "fRecurrence", "WorkspaceLink", "EventType", "UID", "RecurrenceID", "EventCanceled", "Duration", "RecurrenceData", "TimeZone", "XMLTZone", "MasterSeriesItemID", "Workspace", "Course", "CourseLocation"
Next Step 2 is to change the order of the content type. You can cut and paste from the output from step 1, re-order it, and add "{" and "};" around it to create the string array for the ordering you want.
if (list.ContentTypes.Count > 0)
{
SPContentType ct = list.ContentTypes[0]; //Specify the content type here, if you have more than one content type in your list.
string[] fieldnames = { "ContentType", "Title", "Course", "CourseLocation", "EventDate", "EndDate", "Description", "fAllDayEvent", "fRecurrence", "WorkspaceLink", "EventType", "UID", "RecurrenceID", "EventCanceled", "Duration", "RecurrenceData", "TimeZone", "XMLTZone", "MasterSeriesItemID", "Workspace", "Location"};
ct.FieldLinks.Reorder(fieldnames);
web.AllowUnsafeUpdates = true;
ct.Update(true);
web.AllowUnsafeUpdates = false;
}