Dynamically Generated TextBoxes - c#

I need a way of dynamically creating a number of text boxes and accessing their values.
In my form the user enters a number between 1 and 50 and then that number of text boxes must be created with dynamic names ie ingredient1, ingredient2, ingredient3, ...ingredient50 etc.
I have a for loop that will create a number of text boxes using the value, but how do I store the text box value in a string variable?
Here is the for loop currently empty
int i = Form1.ingredientCount;
for (i = 1; i < Form1.ingredientCount; i++)
{
//create new text box
//create new string that then holds value from text box
}
For clarification:
A user enters a number on the previous page.
This number then determines the number of textboxes created and the number of strings created.
The textboxes and strings need to have uniquely generated IDs in a for loop.
I also need another textbox for the weight of each ingredient although I could figure that out myself.
So basically I want each text box and string to be named something like
"input" + i (where i is incrementer)
so that would make the name be "input1", "input2", "input3" and so on.
Same with the string which will contain data from textbox.

I thought i would edit it, as it seems i had misunderstood the question
you could bind it in the form as the following:
public partial class Form1 : Form
{
Recepie pancakes = new Recepie();
IList<UniqueHolder> items = new List<UniqueHolder>();
public Form1()
{
InitializeComponent();
pancakes.Ingredients.Add(new Ingredient { Title = "Milk - 250 gr" });
pancakes.Ingredients.Add(new Ingredient { Title = "Butter - 25 gr" });
pancakes.Ingredients.Add(new Ingredient { Title = "Oil - 1 large spoon" });
pancakes.Ingredients.Add(new Ingredient { Title = "Sugar - 100 gr" });
pancakes.Ingredients.Add(new Ingredient { Title = "Flower - 200 gr" });
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
for (var i = 0; i < pancakes.Ingredients.Count; i++)
{
Ingredient ing = pancakes.Ingredients[i];
TextBox tb = new TextBox { Location = new Point(10, i * 30), Size = new Size(200, 20), Text = ing.Title };
UniqueHolder uh = new UniqueHolder { Ingredient = ing, TextBox = tb };
this.Controls.Add(tb);
}
}
}
The unique holder does the databinding on changes in either ingredient or textbox
public class UniqueHolder : IDisposable
{
public Guid UniqueID { get; set; }
public override bool Equals(object obj)
{
if (obj is UniqueHolder)
{
return Guid.Equals(((UniqueHolder)obj).UniqueID, this.UniqueID);
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return UniqueID.GetHashCode();
}
private TextBox textbox;
public TextBox TextBox
{
get
{
return textbox;
}
set
{
if (object.Equals(textbox, value))
{
return;
}
if (textbox != null)
{
textbox.TextChanged -= OnTextChanged;
}
textbox = value;
if (textbox != null)
{
textbox.TextChanged += OnTextChanged;
}
}
}
private Ingredient ingredient;
public Ingredient Ingredient
{
get
{
return ingredient;
}
set
{
if (object.Equals(ingredient, value))
{
return;
}
if (ingredient != null)
{
ingredient.PropertyChanged -= OnIngredientChanged;
}
ingredient = value;
if (ingredient != null)
{
ingredient.PropertyChanged += OnIngredientChanged;
}
}
}
public UniqueHolder()
{
this.UniqueID = Guid.NewGuid();
}
protected virtual void OnIngredientChanged(object sender, PropertyChangedEventArgs e)
{
if (string.Equals(e.PropertyName, "Title", StringComparison.OrdinalIgnoreCase))
{
if (TextBox == null)
{
return;
}
TextBox.Text = Ingredient.Title;
}
}
protected virtual void OnTextChanged(object sender, EventArgs e)
{
var tb = sender as TextBox;
if (tb == null)
{
return;
}
if (Ingredient == null)
{
return;
}
Ingredient.Title = tb.Text;
}
public void Dispose()
{
Ingredient = null;
TextBox = null;
}
}
And you can get back to the recepie using the ingredients as such
public class Recepie : IDisposable
{
private readonly IList<Ingredient> ingredients = new ObservableCollection<Ingredient>();
public IList<Ingredient> Ingredients
{
get
{
return ingredients;
}
}
protected virtual void OnIngredientsListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (var item in e.OldItems)
{
var ing = item as Ingredient;
if (ing == null)
{
continue;
}
ing.Recepie = null;
}
}
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
var ing = item as Ingredient;
if (ing == null)
{
continue;
}
ing.Recepie = this;
}
}
}
public Recepie()
{
var obs = Ingredients as INotifyCollectionChanged;
if (obs != null)
{
obs.CollectionChanged += OnIngredientsListChanged;
}
}
public void Dispose()
{
int total = Ingredients.Count;
for (int i = total; --i >= 0; )
{
Ingredients.RemoveAt(i);
}
var obs = Ingredients as INotifyCollectionChanged;
if (obs != null)
{
obs.CollectionChanged -= OnIngredientsListChanged;
}
}
}
public class Ingredient : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Recepie recepie;
public virtual Recepie Recepie
{
get
{
return recepie;
}
set
{
if (object.Equals(recepie, value))
{
return;
}
recepie = value;
RaisePropertyChanged("Recepie");
}
}
private string title;
public string Title
{
get
{
return title;
}
set
{
if (string.Equals(title, value))
{
return;
}
title = value;
RaisePropertyChanged("Title");
}
}
protected virtual void RaisePropertyChanged(string propertyName)
{
var local = PropertyChanged;
if (local != null)
{
local.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Rather than creating a string to hold the value from the textboxes, keep the textboxes in a list and get the value out from the Text property when you need it: then you don't need to wire up the TextChanged event etc. Edit: you don't need a string variable to store the textbox text, as you now have a reference to that via the list and the Text property when it's needed.
// a field
List<TextBox> ingredientTextBoxes = new List<TextBox>();
private void Populate(int ingredientCount)
{
for (i = 1; i < ingredientCount; i++)
{
// Assign a consecutive name so can order by it
TextBox tb = new TextBox { Name = "IngredientTextbox" + i};
ingredientTextBoxes.Add(tb);
}
}
// when you want the ingredients
public List<string> GetIngredients
{
List<string> ingredients = new List<string>();
foreach (var tb in ingredientTextBoxes)
{
ingredients.Add(tb.text);
}
return ingredients;
}
// contains
private List<string> GetIngredientsMatching(string match)
{
// Contains really should take a StringComparison parameter, but it doesn't
return ingredientTextBoxes
.Where(t => t.Text.ToUpper().Contains(match.ToUpper()))
.Select(t => t.Text);
}
Edit: if you're going to have multiple values per ingredient then use a User Control which exposes the properties you want - summarising amount, weight, description (e.g. "a pinch" of salt) - in the most convenient way for the code accessing these properties.

Related

Listview in virtual mode - get list of selected items

There is a way to get all items selected with the mouse in a list view when virtual mode is enabled for this winform.
Example of an working code in use, I can retrieve only one selected file for now. Not too much examples finded on the web and could be identified as duplicate but is not conclusive for me, or the answer is to simple.
private void FilesFoundList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
try
{
if (e.ItemIndex >= 0 && e.ItemIndex < ListFilesInfos.Count)
{
try
{
var acc = ListFilesInfos[e.ItemIndex];
//with colors
e.Item = new ListViewItem(new string[] { acc.TagItem, acc.FileName, acc.FilePath.ToString() })
{ Tag = acc,
BackColor = SearchLabColor(0, Path.GetExtension(acc.FileName.ToString()), acc.FilePath.ToString(), acc.FileName.ToString()),
ForeColor = SearchLabColor(1, Path.GetExtension(acc.FileName.ToString()), acc.FilePath.ToString(), acc.FileName.ToString()),
UseItemStyleForSubItems = false
}; // Set Tag object property to our actual AccountInfo object
}
catch { this.Refresh(); }
}
}
catch
{
}
}
private void ShowItemsVirtual(List<SearchFilesInfo> infos)
{
try
{
FilesFoundList.VirtualListSize = infos.Count; // Set number of items in list view
}
catch { this.Refresh(); }
}
private void FilesFoundList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (FilesFoundList.VirtualMode == true)
{
SelectedFiles.GlobalVar = (e.Item.SubItems[2]).Text.ToString() + (e.Item.SubItems[1]).Text.ToString();
}
}
You could abbreviate your code to:
List<multiSearchSelect> multiSearchSelect = new List<multiSearchSelect>();
private void FilesFoundList_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
{
if (FilesFoundList.VirtualMode == true)
{
multiSearchSelect=
FilesFoundList.SelectedIndices
.Select(i=> new multiSearchSelect()
{
fileName = FilesFoundList.Items[i].SubItems[1].Text,
filePath = FilesFoundList.Items[item].SubItems[2].Text
});
}
}
class multiSearchSelect
{
public string fileName { set; get; }
public string filePath { set; get; }
}
I will post my solution that fits to my purpose. I have added ItemsSelectionRangeChanged event and get the list of file selected.
List<multiSearchSelect> multiSearchSelect = new List<multiSearchSelect>();
private void FilesFoundList_VirtualItemsSelectionRangeChanged(object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
{
if (FilesFoundList.VirtualMode == true)
{
multiSearchSelect.Clear();
ListView.SelectedIndexCollection col = FilesFoundList.SelectedIndices;
if (col.Count > 1)
{
foreach (int item in col)
{
multiSearchSelect.Add(new multiSearchSelect
{
fileName = FilesFoundList.Items[item].SubItems[1].Text,
filePath = FilesFoundList.Items[item].SubItems[2].Text
});
}
}
}
}
class multiSearchSelect
{
public string fileName { set; get; }
public string filePath { set; get; }
}

How do I join the selected items in multiple list boxes with the user text entered in text box in c#?

Goal:Is to display Project name, formed by joining list box selected items with user entered text in the text box and display it as a label.
Description: I am creating a windows for App, which has two listboxes displaying Firstname-lbA & Lastname- lbB along with a textbox for the user to enter packet name.
For example: If I select an item(first name)from the listbox A i.e. "XXX", select an item(last name)from the listbox B i.e. "YYY" and enter text in the Textbox i.e. "PKT-100" & click create button I would want to display the Project name as XXX-YYY-PKT-100.
checking conditions:
If no Item in lbA is selected then display:YYY-PKT-100.
If no Item in Lb B is seleected then display :XXX-PKT-100.
If no Text is entered the display: XXX-YYY.
No spaces/double dashes are allowed.
I'd really appreciate if someone could help me with your suggestions.
Thanks!!
Code:
FirstNamespace Project
{
public partial class ProjectTool : Form
{
public List<FirstName> ltfirstname { get; set; }
public List<LastName> ltlastname { get; set; }
public FirstName SelectedFirstname => (FirstName)lbGetFirstName.SelectedItem
public LastName SelectedLastname => (LastName)lbGetLastName.SelectedItem;
public projecTool()
{
InitializeComponent();
ltfirstname = GetFirstNames();
lbGetFirstName.DataSource = ltfirstname;
ltlastname = GetLastNames();
lbGetLastName.DataSource = ltlastname;
}
public List<FirstName> GetFirstNames()
{
List<FirstName> fnames = new List<FirstName>();
using (StreamReader sr = new StreamReader("D:\\FirstNames.csv"))
{
string line;
try
{
while ((line = sr.ReadLine()) != null)
{
string[] columns = line.Replace("\"","").Split(',');
if (columns.Length >= 1)
{
var name = new FirstName();
name.FirstName = columns[0];
fnames.Add(name);
}
}
}
catch (Exception ex) { }
return fnames;
}
}
public List<LastName> GetlastNames()
{
List<LastName> lnames = new List<LastName>();
using (StreamReader sr = new StreamReader("D:\\LastNames.csv"))
{
string line;
try
{
while ((line = sr.ReadLine()) != null)
{
string[] columns = line.Replace("\"","").Split(',');
if (columns.Length >= 1)
{
var lname = new LastName();
lname.LastName = columns[0];
lnames.Add(lname);
}
}
}
catch (Exception ex) { }
return lnames;
}
}
public void CreateprojectName()
{
// Create project name as Firstname-Lastname-Packetname
//if project name already exists then check for correctness/update.
// Check -> if there are double dashes/spaces in the Project name
}
private void lbGetFirstName_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void lbGetlastName_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void txtPacketName_TextChanged(object sender, EventArgs e)
{
}
private void create_projectname_button1_Click(object sender, EventArgs e)
{
}
}
}
Its quite simple for listBox use SelectedItem & for textBox use Text property.
private void create_projectname_button1_Click(object sender, EventArgs e)
{
if (lbGetFirstName.SelectedItems.Count==0)
{
label1.Text = "YYY-PKT-100";
}
if (lbGetlastName.SelectedItems.Count==0)
{
label1.Text = "XXX-PKT-100";
}
if (string.IsNullOrWhiteSpace(textBox1.Text))
{
label1.Text = "XXX-YYY";
}
else
{
label1.Text = lbGetFirstName.SelectedItem + "-" + listBox2.SelectedItem + "-" + lbGetlastName.Text;
}
}

c# getting the right form to show

I have two forms a salaried employee and an hourly employee which has the employees details on it loading from a textfile. In my main form there is a listbox with the names of the employees, once one is clicked, i want to be able to press an edit employee details button on my main form and for the correct form to come up and I am struggling on how to do this. The code for my main form is here:
public partial class MainForm : Form
{
// The file used to store employee details
string employeesFile = "employees.txt";
// The collection used to hold the employee data
Employees employees;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
employees = new Employees();
if (!employees.Load(employeesFile))
{
MessageBox.Show("Unable to load employees file");
}
else
{
PopulateListBox();
}
}
private void PopulateListBox()
{
listBoxEmployees.Items.Clear();
foreach (Employee employee in employees)
{
listBoxEmployees.Items.Add(employee.LastName + "," +
employee.FirstName);
}
listBoxEmployees.SelectedIndex = 0;
}
private void listBoxEmployees_DoubleClick(object sender, EventArgs e)
{ }
private void buttonEdit_Click(object sender, EventArgs e)
{
}
my load method:
{
public bool Load(string employeesFile)
{
bool status = false;
StreamReader inputFile = null;
string inputLine;
if (!File.Exists(employeesFile))
{
return false;
}
try
{
inputFile = new StreamReader(employeesFile);
if (inputFile != null)
{
inputLine = inputFile.ReadLine();
while (inputLine != null)
{
Employee employeeEntry =
EmployeeClass.NewEmployee(inputLine);
if (employeeEntry != null)
{
this.Add(employeeEntry);
}
inputLine = inputFile.ReadLine();
}
inputFile.Close();
}
status = true;
}
catch
{
}
return status;
}
}
the employees class code from the load method:
public class EmployeeClass
{
public static Employee NewEmployee(string employeeData)
{
if (employeeData.Length < 1)
{
return null;
}
switch (employeeData[0])
{
case 'S':
return new SalariedEmployee(employeeData);
case 'H':
return new HourlyEmployee(employeeData);
default:
return null;
the hourly employee form:
public partial class Hourly_Employee : Form {
HourlyEmployee _employeeEntry;
public Hourly_Employee()
{
InitializeComponent();
}
public HourlyEmployee employeeEntry
{
get
{
return _employeeEntry;
}
set
{
_employeeEntry = value;
}
}
private void Hourly_Employee_Load(object sender, EventArgs e)
{
textBoxlastName.Text = _employeeEntry.LastName;
textBoxfirstName.Text = _employeeEntry.FirstName;
textBoxaddress.Text = _employeeEntry.Address;
textBoxpostCode.Text = _employeeEntry.PostCode;
textBoxphoneNumber.Text = _employeeEntry.PhoneNumber;
dateTimePickerdateOfBirth.Text =
_employeeEntry.DateOfBirth.ToString();
textBoxhourlyPay.Text = _employeeEntry.HourlyPay.ToString();
textBoxoverTimePay.Text = _employeeEntry.OvertimePay.ToString();
}
}
and lastly my salaried employee form:
public partial class Salary_Employee : Form
{
SalariedEmployee _employeeEntry;
public SalariedEmployee employeeEntry
{
get
{
return _employeeEntry;
}
set
{
_employeeEntry = value;
}
}
private void Salary_Employee_Load(object sender, EventArgs e)
{
textBoxlastName.Text = _employeeEntry.LastName;
textBoxfirstName.Text = _employeeEntry.FirstName;
textBoxaddress.Text = _employeeEntry.Address;
textBoxpostCode.Text = _employeeEntry.PostCode;
textBoxphoneNumber.Text = _employeeEntry.PhoneNumber;
dateTimePickerdateOfBirth.Text =
_employeeEntry.DateOfBirth.ToString();
textBoxSalary.Text = _employeeEntry.Salary.ToString();
}
any help with this issue would be great!!
The trick is to add the employee objects to the listbox instead of only strings containing the employee names. This allows you to retrieve the selected employee directly from the listbox. Otherwise you would need a way to find the employee object belonging to a name.
Use the type of the selected item to determine the employee type and the employee form.
private void buttonEdit_Click(object sender, EventArgs e)
{
// Get the selected employee from the listBox.
object employee = listBoxEmployees.SelectedItem;
if (employee != null) { // An employee has been selected.
// Use the new C# 7.0 switch syntax in order to switch by employee type.
switch (employee) {
case SalariedEmployee sEmployee:
var sfrm = new Salary_Employee(); // Open the salaried employee form..
sfrm.employeeEntry = sEmployee;
sfrm.Show();
break;
case HourlyEmployee hEmployee:
var hfrm = new Hourly_Employee(); // Open the hourly employee form.
hfrm.employeeEntry = hEmployee;
hfrm.Show();
break;
}
}
}
In case you are using an older C# version you can test a type with
if (employee is SalariedEmployee) {
var frm = new Salary_Employee();;
frm.employeeEntry = (SalariedEmployee)employee;
frm.Show();
} else if (employee is HourlyEmployee) {
var frm = new Hourly_Employee();
frm.employeeEntry = (HourlyEmployee)employee;
frm.Show();
}
By default, an object's ToString method returns the name of the object's type. Enable the listbox to display the employees correctly by overriding the ToString method inherited from object in the common base class Employee.
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}

WPF Menu with visibility permission

I've a WPF application that loads a menu from an XML file, each node as a tag that identifies the user function. Each user has visibility permission that match against the tag defined in the xml file. I wish some help on simplifing that code since I's quite complex and from my point of view poor performing. Consider that the main menu is composed of main items and inside each there're specific areas function. If a user is enabled to at element at list the main menu node is shown otherwise not.
public virtual System.Threading.Tasks.Task<MenuItemNode> RegisterMenu(IDictionary<string,Type> functions)
{
var assembly = Assembly.GetCallingAssembly(); //I should get the module that invoked the base class
string filename = GetFullFileName(assembly, MenuFilename);
return Task.Factory.StartNew<MenuItemNode>(() =>
{
string xmlFileName = string.Format(filename);
var doc = new XmlDocument();
using (Stream stream = assembly.GetManifestResourceStream(xmlFileName))
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
doc.LoadXml(reader.ReadToEnd());
}
}
}
MenuItemNode menu = BuildMenu(doc.SelectSingleNode(#"/Node"), "/", functions);
return menu;
});
}
private string GetFullFileName(Assembly assembly,string filename)
{
var resourceFiles = assembly.GetManifestResourceNames();
return resourceFiles.First(x => x.EndsWith(filename));
}
private MenuItemNode BuildMenu(XmlNode parent, string path, IDictionary<string, Type> functions)
{
Argument.IsNotNull(() => parent);
if (functions == null || (functions.Count == 0)) return null;
MenuItemNode menuItem = null;
string subPath = "Node";
string name = string.Empty;
string tag = string.Empty;
int position = 0;
bool forceVisible = false;
string parameters = string.Empty;
string group = string.Empty;
bool showInDialog = false;
if (parent.Attributes != null)
{
if (parent.Attributes["name"] != null)
name = parent.Attributes["name"].Value;
if (parent.Attributes["tag"] != null)
tag = parent.Attributes["tag"].Value;
if (parent.Attributes["position"] != null)
position = System.Convert.ToInt32(parent.Attributes["position"].Value);
if (parent.Attributes["force_visible"] != null)
forceVisible = Convert.ToBoolean(parent.Attributes["force_visible"].Value);
if (parent.Attributes["parameters"] != null)
parameters = parent.Attributes["parameters"].Value;
if (parent.Attributes["group"] != null)
group = parent.Attributes["group"].Value;
if (parent.Attributes["showindialog"] != null)
showInDialog = Convert.ToBoolean(parent.Attributes["showindialog"].Value);
}
//parent item
if (string.IsNullOrEmpty(tag))
{
menuItem = CreateMenuItem(name, position);
menuItem.ForceVisible = forceVisible;
// menuItem.Group = group;
}
else//child item
{
if (functions.ContainsKey(tag))
{
menuItem = CreateMenuItem(name, tag, position);
menuItem.ForceVisible = forceVisible;
//menuItem.GroupName = group;
menuItem.ShowInDialog = showInDialog;
//menuItem.MenuParameter = GetMenuItemParameters(parameters);
#region Multiple-tag
if ((functions == null) || !functions.Any()) return null;
#endregion
}
else
{
//todo: add-logging
}
}
if (parent.HasChildNodes)
{
foreach (XmlNode child in parent.SelectNodes(subPath))
{
MenuItemNode childMenuItem = BuildMenu(child, subPath, functions);
if (childMenuItem == null) continue;
int childPosition = childMenuItem.SortIndex;
//This to prevent out-of-boundaries exception
if (childPosition > menuItem.Children.Count)
childPosition = menuItem.Children.Count;
menuItem.Children.Insert(childPosition, childMenuItem);
}
}
return menuItem;
}
private MenuItemNode CreateMenuItem(string text, int position)
{
var item = new MenuItemNode();
item.Text = text;
item.SortIndex = position;
return item;
}
private MenuItemNode CreateMenuItem(string text, string tag, int? position)
{
MenuItemNode item = CreateMenuItem(text, (!position.HasValue) ? 0 : position.Value);
item.FunctionTag = tag;
item.SortIndex = (!position.HasValue) ? 0 : position.Value;
return item;
}
And here's the MenuItemNode class
[ContentProperty("Children")]
public class MenuItemNode : INotifyPropertyChanged
{
private string text;
private ICommand command;
private Uri imageSource;
private int sortIndex;
private bool forceVisible;
private bool showInDialog;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
if (this.isChecked != value)
{
this.isChecked = value;
this.RaisePropertyChanged(() => this.IsChecked);
}
}
}
public bool IsSeparator { get; set; }
public MenuItemNode()
{
Children = new MenuItemNodeCollection();
SortIndex = 50;
SetCommand();
}
public MenuItemNode(String path)
: base()
{
Path = path;
}
public MenuItemNodeCollection Children { get; private set; }
public virtual ICommand Command
{
get
{
return command;
}
set
{
if (command != value)
{
command = value;
RaisePropertyChanged(() => this.Command);
}
}
}
public Uri ImageSource
{
get
{
return imageSource;
}
set
{
if (imageSource != value)
{
imageSource = value;
RaisePropertyChanged(() => this.ImageSource);
}
}
}
public string Text
{
get
{
return text;
}
set
{
if (text != value)
{
text = value;
RaisePropertyChanged(() => this.Text);
}
}
}
private MenuGroupDescription group;
public MenuGroupDescription Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
RaisePropertyChanged(() => this.Group);
}
}
}
public int SortIndex
{
get
{
return sortIndex;
}
set
{
if (sortIndex != value)
{
sortIndex = value;
RaisePropertyChanged(() => this.SortIndex);
}
}
}
public string Path
{
get;
private set;
}
public bool ForceVisible
{
get
{
return this.forceVisible;
}
set
{
if (forceVisible != value)
{
this.forceVisible = value;
RaisePropertyChanged(() => ForceVisible);
}
}
}
public bool ShowInDialog
{
get
{
return this.showInDialog;
}
set
{
if (showInDialog = value)
{
this.showInDialog = value;
RaisePropertyChanged(() => ShowInDialog);
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.Name));
}
#endregion
protected virtual void SetCommand()
{
this.Command = FunctionMenuCommands.OpenFunctionCommand;
}
public string FunctionTag { get; set; }
}
In specific what I did is to process each child node then if visible I add it to the collection... do you see any possible better solution?
Thanks
Whoever wrote that code clearly didn't know how to write WPF. In WPF, there is a much simpler option... just use the MenuItem.Visibility property to hide (collapse) MenuItems that users don't have access to. Of course, you'd need some data bind-able security bool properties which you could then data bind to the MenuItem.Visibility property of each MenuItem via a BooleanToVisibilityConverter. Here's a simple example:
<MenuItem Header="Some option" Visibility="{Binding User.Security.HasSomeOptionPermission,
Converter={StaticResource BooleanToVisibilityConverter}}" ... />
If a particular user has the SomeOptionPermission, then the MenuItem will be displayed, otherwise it will be hidden.

Want to do Recursion, load category in undercategory

At the moment I have this Code (Deepth = 2 Categories)
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
if (kategorie.Oberkategorie == null)
{
TreeViewItem newChild = new TreeViewItem();
newChild.Header = kategorie.Bezeichnung;
treeView.Items.Add(newChild);
foreach (Kategorie unterkategorie in mainViewModel.Kategorien)
{
if (unterkategorie.Oberkategorie != null)
{
if (unterkategorie.Oberkategorie.Id == kategorie.Id)
{
TreeViewItem subItem = new TreeViewItem();
subItem.Header = unterkategorie.Bezeichnung;
newChild.Items.Add(subItem);
}
}
}
}
}
}
I would like to make a recursive method, where I could have n Categories in undercategories and so on, I tried things like:
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
FillKategorienTreeView(kategorie);
}
and then:
private void FillKategorienTreeView(Kategorie kategorie)
{
//if (kategorie.Oberkategorie == null)
//{
// TreeViewItem newChild = new TreeViewItem();
// newChild.Header = kategorie.Bezeichnung;
// treeView.Items.Add(newChild);
//}
//else
//{
// if (kategorie.Oberkategorie.Id == kategorie.Id)
// {
// TreeViewItem subItem = new TreeViewItem();
// subItem.Header = kategorie.Bezeichnung;
// newChild.Items.Add(subItem);
// }
//}
}
and other similiar things and it didn't work, I'm not so friendly with recursion but in this case it's indispensable..
There's a Treeview, which has a TopLevel (Maincategory) and can have n under/subcategories.
Hope u can help me
EDIT: The Category Object:
[DataMember]
public int Id
{
get { return _id; }
set
{
if (_id != value)
{
if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
{
throw new InvalidOperationException("The property 'Id' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.");
}
_id = value;
OnPropertyChanged("Id");
}
}
}
private int _id;
[DataMember]
public string Bezeichnung
{
get { return _bezeichnung; }
set
{
if (_bezeichnung != value)
{
_bezeichnung = value;
OnPropertyChanged("Bezeichnung");
}
}
}
private string _bezeichnung;
#endregion
#region Navigation Properties
[DataMember]
public TrackableCollection<Artikel> Artikel
{
get
{
if (_artikel == null)
{
_artikel = new TrackableCollection<Artikel>();
_artikel.CollectionChanged += FixupArtikel;
}
return _artikel;
}
set
{
if (!ReferenceEquals(_artikel, value))
{
if (ChangeTracker.ChangeTrackingEnabled)
{
throw new InvalidOperationException("Cannot set the FixupChangeTrackingCollection when ChangeTracking is enabled");
}
if (_artikel != null)
{
_artikel.CollectionChanged -= FixupArtikel;
}
_artikel = value;
if (_artikel != null)
{
_artikel.CollectionChanged += FixupArtikel;
}
OnNavigationPropertyChanged("Artikel");
}
}
}
private TrackableCollection<Artikel> _artikel;
[DataMember]
public TrackableCollection<Kategorie> Unterkategorie
{
get
{
if (_unterkategorie == null)
{
_unterkategorie = new TrackableCollection<Kategorie>();
_unterkategorie.CollectionChanged += FixupUnterkategorie;
}
return _unterkategorie;
}
set
{
if (!ReferenceEquals(_unterkategorie, value))
{
if (ChangeTracker.ChangeTrackingEnabled)
{
throw new InvalidOperationException("Cannot set the FixupChangeTrackingCollection when ChangeTracking is enabled");
}
if (_unterkategorie != null)
{
_unterkategorie.CollectionChanged -= FixupUnterkategorie;
}
_unterkategorie = value;
if (_unterkategorie != null)
{
_unterkategorie.CollectionChanged += FixupUnterkategorie;
}
OnNavigationPropertyChanged("Unterkategorie");
}
}
}
private TrackableCollection<Kategorie> _unterkategorie;
[DataMember]
public Kategorie Oberkategorie
{
get { return _oberkategorie; }
set
{
if (!ReferenceEquals(_oberkategorie, value))
{
var previousValue = _oberkategorie;
_oberkategorie = value;
FixupOberkategorie(previousValue);
OnNavigationPropertyChanged("Oberkategorie");
}
}
}
private Kategorie _oberkategorie;
This will only work if each category has a list of children or sub categories in the object. If not then you will have to build the list of children for each item.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (Kategorie kategorie in mainViewModel.Kategorien)
{
LoadTreeviewItem(kategorie, null);
}
}
private void LoadTreeviewItem(Kategorie kategorie, TreeViewItem parentItem)
{
//Stop condition
if(kategorie == null) return;
TreeViewItem newChild = new TreeViewItem();
newChild.Header = kategorie.Bezeichnung;
treeView.Items.Add(newChild);
if(parentItem != null) // Add to parent if it is not null
{
parentItem.Items.Add(newChild);
}
else //Otherwise this is the top level so add to treeview
{
treeView.Items.Add(newChild);
}
foreach (Kategorie subkategorie in kategorie.Unterkategorie)
{
LoadTreeviewItem(subkategorie, parentItem);
}
}

Categories

Resources