I have a list of people that I want to display with checkboxes next to their names. When an CheckBoxElement (person) is checked or unchecked, I need to handle the event.
List<CheckboxElement> cbPersonElements = new List<CheckboxElement> ();
CheckboxElement tmpCheckbox = new CheckboxElement ("");
foreach (ABPerson itemPerson in _people) {
tmpCheckbox = new CheckboxElement (itemPerson.LastName);
cbPersonElements.Add(tmpCheckbox);
}
And then I add the list when I create the RootElement:
RootElement _rootElement = new RootElement ("People List"){
new Section ("People"){
cbPersonElements
}
How should I add a handler that will allow me to detected which CheckBoxElement was clicked.
I can't attach one to tmpCheckbox, that value changes with each iteration through the loop.
Seems like it should be simple, but I can't see it.
Thanks.
you should be able to use a ValueChanged handler
foreach (ABPerson itemPerson in _people) {
tmpCheckbox = new CheckboxElement (itemPerson.LastName);
tmpCheckbox.ValueChanged += delegate {
// do something here based on tmpCheckbox.Value
};
cbPersonElements.Add(tmpCheckbox);
}
Related
I have a Treeview with menu content, which is working. I am just not sure how can I implement more root menu to add?
Because this code only shows the "File" menu and all of submenus, but not the other roots.
-Also I would like to ask how could I make these submenus to act like links and create mouselisteners to them? Where is the right place to take the listeners?
The code is the following:
TreeItem<String> treeItemRoot1 = new TreeItem<> ("File");
TreeItem<String> treeItemRoot2 = new TreeItem<> ("Edit");
TreeItem<String> treeItemRoot3 = new TreeItem<> ("View");
TreeItem<String> treeItemRoot4 = new TreeItem<> ("Tools");
TreeItem<String> treeItemRoot5 = new TreeItem<> ("Help");
TreeItem<String> nodeItemA = new TreeItem<>("Item A");
TreeItem<String> nodeItemB = new TreeItem<>("Item B");
TreeItem<String> nodeItemC = new TreeItem<>("Item C");
treeItemRoot1.getChildren().addAll(nodeItemA, nodeItemB, nodeItemC);
TreeView<String> treeView = new TreeView<>(treeItemRoot1);
StackPane.getChildren().add(treeView);
The first part of your question is answered here: Set two root nodes for TreeView
For the second part, it depends on exactly what functionality you want. If you want to respond to a change in the selected item in the tree (this would include the user selecting either with the mouse or by using the keyboard), so can add a listener to the tree's selected item:
treeView.getSelectionModel().selectedItemProperty().addListener((obs, oldItem, newItem) -> {
if (newItem == treeItemRoot1) {
// "file" selected...
} else if (newItem == treeItemRoot2) {
// edit selected
} // etc...
});
If you genuinely want a mouse listener, you need to add a listener to the cell. To do this, use a cell factory:
treeView.setCellFactory(tv -> {
TreeCell<String> cell = new TreeCell<>();
cell.textProperty().bind(cell.itemProperty());
cell.setOnMousePressed(event -> {
TreeItem<String> item = cell.getTreeItem();
if (item == treeItemRoot1) {
// "file" clicked...
} else if (item == treeItemRoot2) {
// etc...
}
}
return cell ;
});
You can probably find ways to organize the code a little more cleanly, and avoid the big if-else construct in either case.
I have foreach loop to listView control, I want to create objects for every listView content, so i want to change the name of the object incrementally by foreach loop
foreach (var item in listViewStates.Items)
{
State s = new State
{
ID = MaxStateID,
Name = listViewStates.Items[0].Text,
WorkflowID = MaxWFID,
DueDate = Convert.ToInt32(listViewStates.SelectedItems[0].SubItems[1].Text),
Priority = Convert.ToInt32(listViewStates.SelectedItems[0].SubItems[2].Text),
RoleID = Convert.ToInt32(listViewStates.SelectedItems[0].SubItems[3].Text),
Status =Convert.ToInt32(listViewStates.SelectedItems[0].SubItems[4].Text)
};
i++;
}
the variable is s from the State Class
You might have the wrong approach. What you need to do with your state object is add it to a collection, and work it from there. It's much easier to track this way.
Example with a local list for use after the loop, in the function:
public void MyFunction()
{
List<State> states = new List<State>();
foreach (var item in listViewStates.Items)
{
State s = new State
{
//Set state properties
};
states.Add(s);
}
//Use your states here, address with brackets
//states[0].ID ...
}
Example with a class-level list for later use outside the function:
List<State> _states;
public void MyFunction()
{
_states = new List<State>();
foreach (var item in listViewStates.Items)
{
State s = new State
{
//Set state properties
};
_states.Add(s);
}
//Now, after calling the function, your states remain
//You can address them the same way as above, with brackets
//_states[0].ID ...
}
I wrote a method which changes backcolor of the rows before painting gridview in devexpress. It works fine but I realized that my code begins slowing down. Then I've found that the event firing continuously. It never stops. How can I handle this? Is there any way to stop firing event manually after gridview painted or should I try to solve this problem with an another event or another method???
Here is my event:
private void gvStep_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
{
try
{
DataRowView drw = (DataRowView)gvStep.GetRow(e.RowHandle);
byte actionTypeID = (byte)drw.Row["ActionType"];
//string colorCode = (new DivaDs()).GetBackColor(actionTypeID);
string colorCode = divaDs.GetBackColor(actionTypeID);
Color backColor = ColorTranslator.FromHtml(colorCode);
e.Appearance.BackColor = backColor;
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message);
}
}
public string GetBackColor(byte actionTypeID)
{
string color = string.Empty;
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[DivaSqlSiteConnString].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand(#"Select BackColor from ActionTypes where ID = #actionTypeID"))
{
SqlParameter param = new SqlParameter("#actionTypeID", actionTypeID);
cmd.Parameters.Add(param);
cmd.Connection = conn;
conn.Open();
color = cmd.ExecuteScalar().ToString();
conn.Close();
}
}
return color;
}
My best guess is that some part of your code is just really slow.
The event only fires for each visible cell in the grid. If you attempt to debug the event, focus will shift to the debugger, and when you return to the application the cells need to be redrawn, causing the event to fire again, thus giving the impression that the event fires continuously. It does not, however.
Here are some pointers to improve performance:
You are constructing a new DivaDs every time the event fires
Instead, consider reusing the same instance of the class as a member variable
What happens in the constructor?
Take a closer look at the GetBackColor method or ColorTranslator.FromHtml and see if any modifications can be made to improve performance.
Update
It appears you are querying the database for each cell in the grid. This is a really bad idea.
A simple solution would be to preload all ActionTypes and their background colors (or at least the subset of ActionTypes that is displayed in the grid) before setting the grid's data source.
// member variable
private Dictionary<byte, Color> actionTypeColorDict;
void BuildActionTypeColorDictionary()
{
string connectionString = ConfigurationManager
.ConnectionStrings[DivaSqlSiteConnString].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = conn.CreateCommand())
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
// load all action type IDs and corresponding background color:
cmd.CommandText = #"SELECT ActionTypeID, BackColor FROM ActionTypes";
DataTable actionTypeTable = new DataTable();
adapter.Fill(actionTypeTable);
// build a dictionary consisting of action type IDs
// and their corresponding colors
actionTypeColorDict = actionTypeTable.AsEnumerable().ToDictionary(
r => r.Field<byte>("ActionTypeID"),
r => ColorTranslator.FromHtml(r.Field<string>("ColorCode")));
}
}
Call the BuildActionTypeColorDictionary method before setting the data source of the grid. In the RowStyle or CustomDrawCell events, use the new dictionary member to determine the background color. See the following modified version of your RowStyle code:
private void gvStep_RowStyle(object sender,DevExpress.XtraGrid.Views.Grid.RowStyleEventArgs e)
{
try
{
DataRow row = gvStep.GetDataRow(e.RowHandle);
if (row == null)
return;
byte actionTypeID = row.Field<byte>("ActionImage");
// look up color in the dictionary:
e.Appearance.BackColor = actionTypeColorDict[actionTypeID];
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message);
}
}
How do you know it's firing continuously? Are you debbuging?
This code runs whenever the grid is redrawn, meaning whenever the form gets focus.
This event runs for each cell - so it will run quite a few times.
If you put a break-point in this event you'll never get out of it. It will break, you will debug, when it's done it will return focus to the form - causing the form to be redrawn using this event and the break-point is reached again.
And just a side note - Whenever I use that event I have to put e.Handled = true; in the code so that the cell isn't "drawn" by anyone but me :)
Finally, I found it. RowStyle event only fires same time with gridview's row count
private void gvStep_RowStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowStyleEventArgs e)
{
try
{
DataRowView drw = (DataRowView)gridView1.GetRow(e.RowHandle);
if (drw == null)
return;
byte actionTypeID = (byte)drw.Row["ActionImage"];
string colorCode = divaDs.GetBackColor(actionTypeID);
Color backColor = ColorTranslator.FromHtml(colorCode);
e.Appearance.BackColor = backColor;
}
catch (Exception ex)
{
XtraMessageBox.Show(ex.Message);
}
}
I have the following code:
Section _section = new Section ("Test");
foreach (ExampleData data in Example.data) {
MessageElement Item = new MessageElement (){
Sender = data.Name,
Subject = data.Value,
Body = data.Description,
Date = data.Modified
} ;
_section.Add(Item);
var root = new RootElement("Item Expanded"){
new Section ("test2"){
new StringElement("Field Name", data.FieldName),
new StringElement("Value", data.Value),
new StringElement("Description", data.Description)
}
} ;
_section.Add(root);
} ;
var _rootElement = new RootElement ("Items") {
_section
} ;
I would like this to work in such a way that when a Message Element is tapped it shows the section with ("test2") that has the same data (e.g. the data was added during the same run of the loop.) I realize this will not happen currently, as it seems the Message Element
requires an Action delegate to do anything on a tap event, plus I'm adding everything to the same section. However, is there any way to replicate the behavior of multiple nested root elements and sections with a Message Element? If I create new pages/screens and try to transition that way, it rests the navigation controller and I lose the use of the back button, even if "push" is set to true.
Not sure what you want exactly. Replace your "Item Expanded" root element code with this to push a dialog viewcontoller on the navigation stack with a backbutton. Ofcourse your DialogViewcontroller should be in a UINavigation controller in the first place for this to work
Item.Tapped += delegate(DialogViewController arg1, UITableView arg2, NSIndexPath arg3)
{
var newDialogVC = new DialogViewController(
UITableViewStyle.Grouped,
new RootElement("Item Expanded")
{
new Section ("test2"){
new StringElement("Field Name", "test"),
new StringElement("Value", "test"),
new StringElement("Description", "test")
}
}
, true);
arg1.NavigationController.PushViewController(newDialogVC,true);
};
given the following code, I am having an issue when clicking on each element. If we assume I have 5 exercises and therefore create 5 elements in the foreach() loop, when the table is rendered and I click on any element, the delegate always gets the exercise of the 5th (last) element.
The elements are displayed properly, each showing the associated exercise's name. It is just the delegate that does not work as expected.
If I do not use a foreach loop and hardcode each element instead it works as expected. However if I cannot dynamically populate the dialogViewController and use the element tapped event for each one, is not good.
private void CreateExerciseTable()
{
Section section = new Section();
foreach (var exercise in exercises)
{
var element = new StyledStringElement(exercise.ExerciseName,
delegate { AddExercise(exercise); })
{
Font = Fonts.H3,
TextColor = UIColor.White,
BackgroundColor = RGBColors.LightBlue,
Accessory = UITableViewCellAccessory.DisclosureIndicator
};
section.Elements.Add(element);
}
var root = new RootElement("Selection") {
section
};
var dv = new DialogViewController(root, true);
dv.Style = UITableViewStyle.Plain;
//Remove the extra blank table lines from the bottom of the table.
UIView footer = new UIView(new System.Drawing.RectangleF(0,0,0,0));
dv.TableView.TableFooterView = footer;
dv.TableView.SeparatorColor = UIColor.White;
dv.TableView.BackgroundColor = UIColor.White;
tableFitnessExercises.AddSubview(dv.View);
}
private void AddExercise(FitnessExercise exercise)
{
NavigationManager.FitnessRoutine.Add(exercise);
PerformSegue(UIIdentifierConstants.SegAddExerciseToFitnessRoutine, this);
}
This is a classic closure bug!
The problem is that you are accessing the loop reference.
Try:
foreach (var exercise in exercises)
{
var localRef = exercise;
var element = new StyledStringElement(exercise.ExerciseName,
delegate { AddExercise(localRef); })
{
Font = Fonts.H3,
TextColor = UIColor.White,
BackgroundColor = RGBColors.LightBlue,
Accessory = UITableViewCellAccessory.DisclosureIndicator
};
section.Elements.Add(element);
}
For more on this see http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx