I have a following problem with Windows Form Application. I have two forms: CategoryTree.cs form with TreeView inside and a ProjectForm.cs with DataGridView inside. I would like to populate DataGridViewComboBoxColumn Collection with TreeView nodes text e.g. I have tree which looks like this:
Science Fiction
Movie1
Movie2
Horror
Movie1
Movie2
Action
Movie1
Movie2
and so on. I want those categories to be Items in the ComboBoxColumn. My code looks as follows in the CategoryTree form
public partial class CategoryTree : Form
{
//adding nodes to the tree
private void button2_Click(object sender, EventArgs e)
{
TreeNode newone = new TreeNode();
newone.ForeColor = Color.Orange;
newone.NodeFont = new Font(catTreeView.Font, FontStyle.Bold);
newone.Text = nameBox.Text;
catTreeView.Nodes.Add(newone);
//and code for adding child and grandchild and ...
}
//other stuff
}
In the DataGridView I have the following method
public void AddComboBox()
{
int i;
CategoryTree cat_Form = new CategoryTree();
//Set the cat_Form Active
cat_Form = ActiveForm as CategoryTree;
if (cat_Form != null)
{
i = cat_Form.catTreeView.Nodes.Count; //here i get exception
if(i != 0)
{
var newone2 = new DataGridViewComboBoxColumn();
newone2.HeaderText = "Main category";
newone2.Name = "ColNr_" + nofCols;
string comboTxt;
for(int j=0; j<i; j++){
comboTxt = catTreeView.Nodes[j].Text;
newone2.Items.Add(comboTxt);
}
mainProjectGrid.Columns.Add(newone2);
nofCols += 1;
}
}
}
Unfortunately this code generates 'System.NullReferenceException'. The catTreeView modifier is set to 'public'. I had many different approaches to the problem, but none of them worked.
As you may see my questoin is - how can I get to the catTreeView object from the ProjectForm form and populate combobox?
I'm absolute beginner so answers with example code will be always appreciated.
To Whom It May Concern. I found the solution to this problem. In TreeView I added one button programed this way
private void applyBtn_Click(object sender, EventArgs e)
{
ProjectForm newProject1 = new ProjectForm( catTreeView );
newProject1.MdiParent = this.ParentForm;
newProject1.Text = "blabla";
newProject1.Show();
}
Next I added this to the ProjectForm.cs
public ProjectForm(TreeView catView)
{
InitializeComponent();
holalala = catView;
}
public void AddComboBox()
{
int i;
if (holalala != null)
{
i = holalala.Nodes.Count;
if (i != 0)
{
var newone2 = new DataGridViewComboBoxColumn();
newone2.HeaderText = "Main category";
newone2.Name = "ColNr_" + nofCols;
string comboTxt;
for (int j = 0; j < i; j++)
{
comboTxt = holalala.Nodes[j].Text;
newone2.Items.Add(comboTxt);
}
mainProjectGrid.Columns.Add(newone2);
nofCols += 1;
}
}
}
This solution is pretty simple and works fine. I think I can now add few lines to not just add Columns but also to update them with new Nodes that may appear in the TreeView. I will work on that later :).
Related
I have done the following code and works well. I am wondering how I can do a for loop to clean this code from 38 lines into 2 lines.
s0s.Text = seg[0].start.ToString("X8");
s0e.Text = seg[0].end.ToString("X8");
s1s.Text = seg[1].start.ToString("X8");
s1e.Text = seg[1].end.ToString("X8");
// .. many more ..
s19s.Text = seg[19].start.ToString("X8");
s19e.Text = seg[19].end.ToString("X8");
I can obviously do the seg[i] substitution, but how do i do it with the text boxes?
I suppose you could use the Controls property and call OfType<T>() to get all the instances of TextBoxes in your Form instance
Filters the elements of an IEnumerable based on a specified type.
Then convert the results to a Dictionary based on the control Name
// this could potentially be done in the constructor
var dict = Controls.OfType<TextBox>().ToDictionary(x => x.Name);
for (int i = 0; i < 19; i++)
{
dict[$"s{i}s"].Text = $"{seg[i].Start:X8}";
dict[$"s{i}e"].Text = $"{seg[i].End:X8}";
}
Note : This code is untested and only a guide to a possible solution
I'd be tempted to do it this way. First create two lists of your controls, the starts and the ends:
var starts = new List<TextBox>
{
s0s,
s1s,
//...
s19s
};
var ends = new List<TextBox>
{
s0e,
s1e,
//...
s19e
};
Then loop over each list:
var i = 0;
foreach (var start in starts)
{
start.Text = seg[i].start.ToString("X8");
++i;
}
i = 0;
foreach (var end in ends)
{
start.Text = seg[i].end.ToString("X8");
++i;
}
Your indexes and control numbers would need to line up perfectly though.
Note: Like TheGeneral's code, this is untested (neither of us wants to create a form with 38 text boxes with specific names)
Based on the textboxes names I would suggest alternative approach to use control designed to display collection of things - DataGridView would be one of the options.
With data binding you can achieve little bit more maintainable code
public class MyItem
{
public int Start { get; set; }
public int End { get; set; }
}
In the form create a datagridview with two bounded columns, you can do this in winforms designer without manually writing the code below.
// constructor
public MyForm()
{
var startColumn = new DataGridViewTextBoxColumn();
startColumn.DataPropertyName = "Start"; // Name of the property in MyItem class
startColumn.DefaultCellStyle.Format = "X8";
var endColumn = new DataGridViewTextBoxColumn();
endColumn.DataPropertyName = "End"; // Name of the property in MyItem class
endColumn.DefaultCellStyle.Format = "X8";
myDataGridView.Columns.AddRange(startColumn, endColumn);
myDataGridView.AutoGenerateColumns = false;
}
private void Form1_Load(object sender, EventArgs e)
{
var items = new List<MyItem>
{
new MyItem { Start = 10, End = 20 },
new MyItem { Start = 11, End = 19 },
new MyItem { Start = 12, End = 18 }
};
myDataGridView.DataSource = items;
}
firstly when you create they variables insert them all to an array. then run a loop as following:
for (int i; int < 19(your list); i++)
{
your list[i].Text = seg[i].start.ToString("X8");
your list[i].Text = seg[i].end.ToString("X8");
}
I want to create a webform with 4 types of phones like: LG, xiaomi, samsung and iphone. They will be in an Array and I will insert them into dynamic radiobuttonList in the page init.
Also, the user will have a textbox where he will put an amount of money he has. The user will also have a button that will calc if he have the budget for the selected phone from the list.
After the user selects the phone, write in the budget and press the button
he will get "in budget" or "not enough budget".
The class have property of the array to insert the all the array from the page init and will have 2 functions:
One function will take the budget number > will go to the 2nd function that will see the selected phone and the budget > do its calcs and return the result into the 1st func that will give the feedback.
Now where I am stuck:
if the class isnt made global - and i put it in init or in button click - it wont work, so im looking for a way to make it work but without putting it global
so far i managed to inject the selected value into a class property and than compare - but i want to know if there is a way that this can happen with array inside class property
maybe if anyone can help me out and refer me to a guide where i can learn more about this subject (how inject selected value into function of a class and etc) ill be glad! as everything i see is C# with console but i work with ASP.NET WEB APPLICATION (.netframework)
enter code here
namespace gfjsr{
public partial class WebForm1 : System.Web.UI.Page{
phone InsertUserInfo = new phone();
protected void Page_init(object sender, EventArgs e){
string[] myArr = new string[] { "samsung", "IPHONE", "XIAOMI","LG"};
RadioButtonList phoneList = new RadioButtonList();
phoneList.ID = "radioList";
for (int i = 0; i< myArr.Length; i++)
{
ListItem li = new ListItem();
li.Text = myArr[i];
li.Value = i.ToString();
phoneList.Items.Add(li);
}
Panel1.Controls.Add(phoneList);
Label budgetLb = new Label();
budgetLb.ID = "budglb";
budgetLb.Text = "write your budget";
Panel1.Controls.Add(budgetLb);
TextBox insertBudg = new TextBox();
insertBudg.ID = "budgTxt";
Panel1.Controls.Add(insertBudg);
Button myBtn = new Button();
myBtn.ID = "btn1";
myBtn.Click += new EventHandler(btn1_click);
myBtn.Text = "result";
Panel1.Controls.Add(myBtn);
Label Labelfeedback = new Label();
Labelfeedback.ID = "feedback";
Labelfeedback.Text = "";
Panel1.Controls.Add(Labelfeedback);
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btn1_click(object sender, EventArgs e)
{
InsertUserInfo.phoneChosen = ((RadioButtonList)FindControl("radioList")).SelectedItem.Text;
double UserBudget =
Convert.ToDouble(((TextBox)FindControl("budgTxt")).Text);
InsertUserInfo.BudgetYN(UserBudget);
((Label)FindControl("feedback")).Text = InsertUserInfo.feedback; }}}
namespace gfjsr{
public class phone{
private string _phoneChosen;
public string phoneChosen
{
get { return _phoneChosen; }
set { _phoneChosen = value; }
}
private string _feedback;
public string feedback
{
get { return _feedback; }
set { _feedback = value; }
}
public double Func1(string x)
{
double phonePrice = 0;
if( x == "samsung")
{
phonePrice = 4000;
}
if (x == "IPHONE")
{
phonePrice = 3500;
}
if (x == "XIAOMI")
{
phonePrice = 3000;
}
if (x == "LG")
{
phonePrice = 2000;
}
return phonePrice;
}
public void BudgetYN(double y)
{
if(y >= Func1(_phoneChosen))
{
_feedback = "positive";
}
else
{
_feedback = "no";
}
}
}
}
I have a little problem, I'm trying update my listView(listClients)
private ListView initializeLstView()
{
var lstView = new ListView();
var lstViewItem = new ListViewItem();
for (uint i = 0; i < 18; ++i)
{
lstViewItem = lstView.Items.Add("Free");
lstViewItem.SubItems.Add("Free");
}
return (lstView);
}
private ListView setNamesToLstView()
{
var lstView = initializeLstView();
try
{
for (uint i = 0; i < 18; ++i)
{
lstView.Items[(int)i].Text = clients.GetName(i);
lstView.Items[(int)i].SubItems[1].Text = "{" + i.ToString() + "}";
}
lstView.Update();
}
catch (Exception a)
{
Interaction.MsgBox(a.ToString());
}
return (lstView);
}
private void btnRefreshClients_Click(object sender, EventArgs e)
{
listClients = setNamesToLstView(); // Here, no update
}
But here, my listView contains nothing, no update / no refresh, why ?
How can I resolve this ?
The problem is you are adding items to another list view.
listClients is a member variable which points to a ListView which you previously added to Controls collection of your form. When you want to add items to that list view, you should add items exactly to that object using listClients.Items.Add(...).
But currently you have created a ListView in the method and added items to it and at last returned it and assigned it to listClients. It doesn't make your new created list view be shown on your form. It makes listClients variable only points to new created control, Whilst you are seeing the previous created ListView.
I a beginner in C# and WPF. I'm programming plugin for a node based software called vvvv. I have implemented sliders, buttons and other simple ui elements. The following code shows how a sliders node look in c# :
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xml;
using VVVV.PluginInterfaces.V2;
namespace VVVV.Packs.UI.Nodes.WPF
{
[PluginInfo(Author = "lecloneur", Category = "WPF", Help = "WPF Slider", Name = "Slider", AutoEvaluate = false)]
public class WPFSlider : GenericNode, IPluginEvaluate
{
[Input("SizeX", DefaultValue = 120, Order = 9, MinValue = 0)]
public IDiffSpread<int> SizeX;
[Input("SizeY", DefaultValue = 120, Order = 9, MinValue = 0)]
public IDiffSpread<int> SizeY;
[Input("Orientation", Order = 1, DefaultEnumEntry = "Horizontal")]
public IDiffSpread<Orientation> OrientationIn;
[Output("Value", Order = 2)]
public ISpread<double> ValueOut;
int elements_count = 0;
public void Evaluate(int SpreadMax)
{
UIElementOut.SliceCount = SpreadMax;
ValueOut.SliceCount = SpreadMax;
for (int i = 0; i < SpreadMax; i++)
{
if (UIElementOut == null || !(UIElementOut[0] is Slider) || elements_count < SpreadMax || OrientationIn.IsChanged || SizeX.IsChanged || SizeY.IsChanged)
{
CreateElement(i);
}
OutputData(i);
Transformation(i, (Slider)UIElementOut[i]);
}
elements_count = SpreadMax;
}
private void CreateElement(int i)
{
UIElementOut[i] = new Slider();
var uiElement = (Slider)UIElementOut[i];
uiElement.Minimum = 0;
uiElement.Maximum = 1;
uiElement.Orientation = OrientationIn[i];
uiElement.IsMoveToPointEnabled = true;
uiElement.Width = SizeX[i]; ;
uiElement.Height = SizeY[i];
uiElement.VerticalAlignment = VerticalAlignment.Center;
uiElement.HorizontalAlignment = HorizontalAlignment.Center;
XmlReader XmlRead = XmlReader.Create("Styles/SliderStyle.xaml");
ResourceDictionary myResourceDictionary = (ResourceDictionary)XamlReader.Load(XmlRead);
XmlRead.Close();
Style uiElementStyle = myResourceDictionary["SliderStyle"] as Style;
uiElement.Style = uiElementStyle;
}
private void OutputData(int i)
{
var uiElement = (Slider)UIElementOut[i];
ValueOut[i] = uiElement.Value;
}
}
}
Now I'm trying to implement a tabcontrol where I could dynamically create tabitem and input UIElement into it. As far as I understand, I can only add one things to a tabitem. So I was thinking about creating a grid everytime I need to and fill it with all the incoming UIElement.
public void Evaluate(int SpreadMax)
{
SpreadMax = 1;
UIElementOut.SliceCount = 1;
for (var i = 0; i < SpreadMax; i++)
{
if (UIElementOut == null || !(UIElementOut[i] is TabControl))
UIElementOut[i] = new TabControl();
var uiElement = (TabControl)UIElementOut[i];
uiElement.Height = 200;
uiElement.Width = 500;
}
Grid grid;
int[] _elementCounts = new int[_elementInputs.SliceCount];
for (var i = 0; i < _elementInputs.SliceCount; i++)
{
if (_elementInputs[i] == null || !(_elementInputs[i] is UIElement))
{
grid = new Grid();
for (var j = 0; j < _elementInputs[i].IOObject.SliceCount; j++)
{
if (_elementInputs[i].IOObject[j] != null)
{
UIElement test = new UIElement();
test = _elementInputs[i].IOObject[j];
grid.Children.Add(test);
}
}
_elementCounts[i] = _elementInputs[i].IOObject.SliceCount;
ValueOut[i] = _elementCounts[i];
if (((TabControl)UIElementOut[0]).Items.Count <= i)
{
((TabControl)UIElementOut[0]).Items.Add(new TabItem { Header = _nameInputs[i].IOObject[0], Content = grid });
}
if (_nameInputs[i].IOObject.IsChanged)
{
((TabItem)((TabControl)UIElementOut[0]).Items[i]).Header = _nameInputs[i].IOObject[0];
}
if (_elementInputs[i].IOObject.IsChanged)
{
((TabItem)((TabControl)UIElementOut[0]).Items[i]).Content = grid;
}
}
}
for (var i = ((TabControl)UIElementOut[0]).Items.Count - 1; ((TabControl)UIElementOut[0]).Items.Count > _elementInputs.SliceCount; i--)
{
((TabControl)UIElementOut[0]).Items.RemoveAt(i);
}
}
I searched a lot but can't find any idea how to solve the error. Apparently adding elements to a the grid throw "specified element is already the logical child of another element";
Hi please try the next method on a several visual objects (child) and check if the resulted object is the same reference. Here is a usefull link with explanations and more...
Extension class code:
public static class VisualTreeHelperExtensions
{
public static T FindParent<T>(this DependencyObject child) where T : DependencyObject
{
while (true)
{
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
child = parentObject;
}
}
}
Example:
var dataGrid1 = dependencyObject1.FindParent<DataGrid>();
var dataGrid2 = dependencyObject2.FindParent<DataGrid>();
var isSameObject = dataGrid1 == dataGrid2;
Updates
The grid can contains a large number of elements but the only last will be visible to user.
The error is coming from the elemnt you want to add itself, that elemnt is belong to another control (some another control has the element as a child).
Find the parent element of the element you want to add, remove the element from the current parent's children collection, and add this element as the new child of your grid.
Try to use snoop to figure out who is the parent of your element (containing in _elementInputs).
Here are some useful links (first, second).
Update 2
As I can understand you have a third party infrastructure in your project because I can't resolve the type of _elementInputs and UIElementOut collections.
Since the _elementInputs is a field, I still can't understand where is _elementInputs came from (can't see that in code).
The code to add a completely new element is wrong:
Correct code(in my opinion)
//here is in my opinion the correct algorithm in this case
var elementFromInputs = _elementInputs[i] as UIElement;
if (elementFromInputs == null) continue;
//try to find parent of type Panel
var parentPanel = elementFromInputs.FindParent<Panel>();
//try to find parent of type ContentControl
var parentContentControl = elementFromInputs.FindParent<ContentControl>();
if (parentPanel == null && parentContentControl == null)
{
//add if there is no any parents
grid.Children.Add(elementFromInputs);
}
if (parentPanel != null)
{
//remove element from parent's collection
parentPanel.Children.Remove(elementFromInputs);
}
if(parentContentControl != null)
{
//reset parent content to release element
parentContentControl.Content = null;
}
grid.Children.Add(elementFromInputs);
Update 3
You've pasted the code (from the correct code section) inside the if which condition is the _elementInputs[i] == null || !(_elementInputs[i] is UIElement) that means filtering all your UIElements out of the scope. Since I'm not familiar with the vvvv concepts I don't know what do you have inside the _elementInputs array, but if you have the UIElements there you need past the code I gave you before the if with condition _elementInputs[i] == null || !(_elementInputs[i] is UIElement).
Please update your question with the next clarifications:
1. What is inside the _elementInputs[i]?
2. What is inside the _elementInputs[i].IOObject?
3. What are UIElements you want to add to the grid?
4. Please run the next method and write me the comment what do you have in your grid and TabControl controls.
Test code
public void Evaluate(int SpreadMax)
{
SpreadMax = 1;
UIElementOut.SliceCount = 1;
for (var i = 0; i < SpreadMax; i++)
{
if (UIElementOut == null || !(UIElementOut[i] is TabControl))
UIElementOut[i] = new TabControl();
var uiElement = (TabControl)UIElementOut[i];
uiElement.Height = 200;
uiElement.Width = 500;
}
Grid grid = new Grid();
var listOfElements = new List<UIElements>
{
new Button {Background = Brushes.Tomato, Content = "Click Me"},
new Button {Background = Brushes.Yellow, Content = "Click Me"},
new Button {Background = Brushes.Green, Content = "Click Me"},
new Button {Background = Brushes.Blue, Content = "Click Me"}
};
listOfElements.ForEach(button => grid.Children.Add(button));
((TabControl)UIElementOut[0]).Items.Add(new TabItem { Header = "Objects", Content = grid });
}
I'll be glad to help if you will have problems with the code.
Regards.
I have a bunch of code that dynamicly creates some controls. It looks in a folder and lists the filenames in it. For each file in the folder it creates a checklistbox item, listbox item and two checkboxes. This is working great and as intended:
private void getAllFiles(string type)
{
try
{
string listPath = "not_defined";
if (type == "internal_mod")
{
int first_line = 76;
int next_line = 0;
int i = 0;
CheckBox[] chkMod = new CheckBox[100];
CheckBox[] chkTool = new CheckBox[100];
listPath = this.internalModsPath.Text;
string[] filesToList = System.IO.Directory.GetFiles(listPath);
foreach (string file in filesToList)
{
if (!internalModsChkList.Items.Contains(file))
{
internalModsChkList.Items.Add(file, false);
string fileName = Path.GetFileName(file);
internalModNameList.Items.Add(fileName);
//-----------------
// Draw Checkboxes
//-----------------
chkMod[i] = new CheckBox(); chkTool[i] = new CheckBox();
chkMod[i].Name = "modChk" + i.ToString(); chkTool[i].Name = "modChk" + i.ToString();
//chkMod[i].TabIndex = i; //chkTool[i].TabIndex = i;
chkMod[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top); chkTool[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top);
chkMod[i].Checked = true; chkTool[i].Checked = false;
chkMod[i].AutoCheck = true; chkTool[i].AutoCheck = true;
chkMod[i].Bounds = new Rectangle(549, first_line + next_line, 15, 15); chkTool[i].Bounds = new Rectangle(606, first_line + next_line, 15, 15);
groupBox7.Controls.Add(chkMod[i]); groupBox7.Controls.Add(chkTool[i]);
//-----------------
next_line += 15;
i++;
}
}
}
Now my problem is that I also want the user to be able to delete all these thing again based on the checklistbox' checked items.. I have no problems deleting the items in the checklistbox or the items in the listbox, but I want to remove the two checkboxes I create too ..
This is what I got to remove the items in the checklistbox, and the listbox
private void internalModListDel_btn_Click(object sender, EventArgs e)
{
int count = internalModsChkList.Items.Count;
for (int index = count; index > 0; index--)
{
if (internalModsChkList.CheckedItems.Contains(internalModsChkList.Items[index - 1]))
{
internalModsChkList.Items.RemoveAt(index - 1);
internalModNameList.Items.RemoveAt(index - 1);
groupBox7.Controls.Remove(modChk[index - 1]);
}
}
}
As you can see I have also tried to write something to remove the checkbox but it doesn't work and I have no idea how to make it work
Can you assist ?
Try using UserControls.
Use the ListBox controller to show those UserControls,
The user control can be built with those checkboxes, and the labels you want .
Another suggestion is to bind this list to an ObservableCollection which will contain the UserContorols you have created.
This way, it will be much more simlpe to add/remove/change the items inside.