WinForms - Baffled - How to Handle Certain Controls Dynamically - Properly - c#

I have a System.Windows.Form class (my main class). There is a RootMenu object. This is my own custom object. I'm trying to loop through the RootMenu object and on each pass add a ToolStripMenuItem to a ContextMenuStrip (which I named ContextMenu). The RootMenu object contains a List. Links have Names and Urls (both strings).
When the form loads my "Factory" class loads me up a RootMenu object, which I then pass into the ProcessMenu method.
Code Excerpt Here:
private void ProcessMenu(RootMenu rm)
{
foreach (var lnk in rm.Links)
{
var tsmi = new ToolStripMenuItem(lnk.Name, null, new EventHandler(Navigate));
tsmi.ToolTipText = lnk.Url;
ContextMenu.Items.Add(tsmi);
}
}
private void Navigate(object sender, EventArgs e)
{
var tsmi = (ToolStripMenuItem) sender;
System.Diagnostics.Process.Start(tsmi.ToolTipText);
}
Do you see how I have to store the lnk.Url in the ToolTipText? In the VB6 days all the controls had the "tag" property. You used to be able to stuff extra stuff into the control that you would need later on. I don't want to use the tooltip for this, but what are my alternatives? Storing all the Urls in a Hash/Dictionary using the name as a key? I may not always have unique names, so I would like to avoid this route. What is the proper way to handle this in .NET? Maybe I missing some basic concept I have never been exposed to.

ToolStripMenuItem has a Tag property:
tsmi.Tag = lnk.Url;
In fact, quite a few Windows Forms controls have it.

Just inherit the old class and stick a Tag property in there:
public class myToolStripMenuItem : ToolStripMenuItem
{
public object myTag { get; set; }
}

Create your own object inheriting from ToolStripMenuItem and add any custom properties....
private void ProcessMenu(RootMenu rm)
{
foreach (var lnk in rm.Links)
{
var tsmi = new UrlToolStripMenuItem(lnk.Name, null, new EventHandler(Navigate))
{
Url = lnk.Url,
};
ContextMenu.Items.Add(tsmi);
}
}
private void Navigate(object sender, EventArgs e)
{
var tsmi = (UrlToolStripMenuItem)sender;
System.Diagnostics.Process.Start(tsmi.Url);
}
public class UrlToolStripMenuItem : ToolStripMenuItem
{
public UrlToolStripMenuItem(string text, Image image, EventHandler onClick) : base(text, image, onClick)
{
}
public string Url { get; set; }
}

Related

How to create an array of Circular Progress Bars?

I would like to know how can I create an array of Circular Progress Bars and access its properties within the array, like CircularProgressBar[i].text and CircularProgressBar[i].value.
I tried to use object array but I can't access the properties of circular progress bar within the for loop, what I also tried is to make to arrays one is type string and it has all the CircularProgressBars.text, and the Other one is the type INT which contains CircularProgressBar.value, but it didn't work, nothing changed in the form.
CircularProgressBar.CircularProgressBar[] cbpArray = new CircularProgressBar.CircularProgressBar[] { shifts1.circularProgressBarNeeShift1, shifts1.circularProgressBarNeeShift2, shifts1.circularProgressBarNeeShift1 };
public Form1()
{
InitializeComponent();
}
image
Okay, since you are trying to reference an item that is in a user control you need to add an accessor inside your UserControl .cs file. I believe it is called shift1.cs for you.
Note: cpb is the name that I gave the CircularProgressBar inside the UserControl shifts1.
public partial class shifts1 : UserControl
{
public CircularProgressBar.CircularProgressBar CPB
{
get
{
return cpb;
}
set
{
cpb = value;
}
}
public shifts1()
{
InitializeComponent();
}
}
Then you will use the name for each user control from your form. In my case I named mine formCPB1 and formCPB2.
CircularProgressBar.CircularProgressBar[] arr = new CircularProgressBar.CircularProgressBar[]
{ formCPB1.CPB, formCPB2.CPB };
Once you have the array you can access them by using the name of the array.
arr[0].Text = "test";
arr[1].Text = "asdf";

How Do I Filter A CollectionView Of Objects Based On The Properties Of The Objects?

In my project I have a collection view generated from an observablecollection of objects, which is then used as the data source of a listview. Each object has a name property and an icon property, I need to be able to filter the view based on the name of the object, any help would be appreciated.
I ended up just bodging it rather than using a proper method since it's just for my A-Level project. The code I used was:
Cards = new ObservableCollection<Card>(LoadCards());
FilteredCards = new ObservableCollection<Card>();
Search();
void Search()
{
foreach (var Card in Cards)
{
if (Card.Name.Contains(SearchBox.Text))
{
FilteredCards.Add(Card);
}
}
}
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
{
FilteredCards.Clear();
Search();
}

Use combobox value in different WPF form class

I have a WPF window which the user can select items in a combobox drop down.
Once they press a button, another WPF window will open. I want to be able to use the drop down selection value in the other WPF window class.
I've just started working with WPF windows so apologies if this should be simple.. below is what I've tried but had no luck with.
A class which holds the combobox values:
public class ComboSelection
{
public string cFunction { get; set; }
public string cItem { get; set; }
}
Creating an instance of the class and assigning the properties values and opening the second WPF window:
private void Button2_Click(object sender, RoutedEventArgs e)
{
ComboSelection combo = new ComboSelection();
combo.cFunction = ComboBox3.Text;
combo.cItem = ComboBox2.Text;
Pick_Item pi = new Pick_Item();
pi.Show();
}
When I try to reference the class in the other WPF window class, I get the error An object reference is required for the non-static field, method or property.
I tried making the properties static, and then that shows a compile error of Member 'myProject.ComboSelection.cFunction.get' cannot be accessed with an instance reference; qualify it with a type name instead.
Any help is greatly appreciated.
Add a ComboSelection parameter to the Pick_Item constructor and pass combo into your new instance of Pick_Item
class Pick_Item
{
private ComboSelection _comboSelection;
public Pick_Item(ComboSelection comboSelection)
{
_comboSelection = comboSelection;
}
}
...
Pick_Item pi = new Pick_Item(combo);
pi.Show();
Now your Pick_Item class has access to the ComboSelection as a class-level variable.

Binding from just created class

I have a class called Channel, that has properties: channelName, (more but irrelevant for this question) , and two List<double> (xValues, yValues).
public class Channel
{
public string channelName;
public List<double> xValues= new List<double>();
public List<double> yValues= new List<double>();
}
I also have a class called File, there are properties as: fileName, ObservableCollection<Channel> listOfChannels. File has a method called read(); that creates internally objects of class Channel for reading the data, depending of the data there will be a variable number of channel, and stores in the Lists xValues and yValues the data.
public class File
{
public string fileName{ get; set; }
public ObservableCollection<Canal> channels{ get; set; }
public void read() {//stuff}
}
In my program I've created a ComboBox that is binded to that data this way:
<ComboBox x:Name="comboFile"
ItemsSource="{Binding myListOfChannels}"
DisplayMemberPath="channelName"
SelectedValuePath="channelName"
SelectedItem="{Binding selectedChannel}" />
Where myListOfChannels and selectedChannel are defined as:
public ObservableCollection<Canal> myListOfChannels { get; set; }
public Canal selectedChannel { get; set; }
I instantiated them properly later in the code.
When I click a button the file loads and it creates a new object of class File. This is my exampleFile.
private void openButton_Click(object sender, RoutedEventArgs e)
{
File exampleFile= new File();
Channel exampleChannel= new Channel();
exampleFile.fileName= #"C:\Users\Path\myFile.txt"; //I haven't created OpenDialog yet
exampleFile.read();
myListOfChannels = new ObservableCollection<Channel>();
foreach (Channel mychannel in exampleFile.channels)
{
myListOfChannels .Add(mychannel);
}
selectedChannel = exampleFile.channels[0];
comboFile.DataContext = this;
}
This is a translation from other language, there can be slight errors in syntax, but it works.
Please, I don't want a complete redesign of this, there are other constrains.
My question is about if it's possible to remove the redundant assignation (myListOfChannels and selectedChannel, the foreach loop, etc) and directly bind the data from my just created exampleFile, something like this:
<ComboBox x:Name="comboFile"
ItemsSource="{Binding exampleFile.channels}"
DisplayMemberPath="exampleChannel.channelName"
SelectedValuePath="exampleChannel.channelName"
SelectedItem="{Binding selectedChannel}" />
I'm extremely newbie here, so if you could actually help me with the writing that would be great. I've read several tutorials of data-binding but I can't figure out this.
BTW. This may be important: All this code is inside a UserControl. In my MainWindow.xaml is only a instance of that UserControl.
I've tried my best to explain what I want but if something isn't clear just ask it. Thank you.
When you use a Path on a binding (e.g. {Binding Something} is equivalent to {Binding Path=Something}) or e.g. DisplayMemberPath, it must refer to a property. Not a field (e.g. public string Something;), or a local variable (e.g. void SomeMethod() { string something; }), but a public property (e.g. public string Something { get; set; }).
In your code, exampleFile and exampleChannel are, as far as I can see, local variables. Also, exampleChannel doesn't appear to be used. You could fix it with something like this:
public File ExampleFile { get; set; }
private void openButton_Click(object sender, RoutedEventArgs e)
{
ExampleFile = new File();
ExampleFile.fileName= #"C:\Users\Path\myFile.txt"; //I haven't created OpenDialog yet
ExampleFile.read();
myListOfChannels = new ObservableCollection<Channel>();
foreach (Channel mychannel in ExampleFile.channels)
{
myListOfChannels.Add(mychannel);
}
selectedChannel = ExampleFile.channels[0];
comboFile.DataContext = this;
}
(as a convention, properties in .NET use PascalCase, so it's ExampleFile, not exampleFile)
Also of note: if the property can change, and you want the binding to automatically update when that happens, you should implement INotifyPropertyChanged on the class(es) you're binding to (in this case, that looks like File, Channel, and MainWindow).

Public variable invoking incorrect result

public partial class ThanglishToTamilGUI : Form
{
public string anz;
public ThanglishToTamilGUI()
{
InitializeComponent();
}
public void btnConvertToBraille_Click(object sender, EventArgs e)
{
anz = richTextBoxTamil.Text.ToString();
GUI.TamilToBrailleGUI c1 = new GUI.TamilToBrailleGUI();
c1.Visible = true;
}
}
I need to pass my richtextbox (richTextBoxTamil) content to variable call anz.
I am retrriving anz variable in other form as form load event:
private void TamilToBrailleGUI_Load(object sender, EventArgs e)
{
ThanglishToTamilGUI tt = new ThanglishToTamilGUI();
String apper = tt.anz;
richTextBoxTamil.Text = apper;
}
My Problem:
I am getting null values as result. Since if I assigned any values that invoked correctly.
public partial class ThanglishToTamilGUI : Form
{
public string anz = "Hai";
public ThanglishToTamilGUI()
{
InitializeComponent();
} ...
Here my ans value is passed as "Hai". But my requirement is to get what ever the content in the richTextBoxTamil and pass it to that public variable call anz. What went wrong here please help me.
Thank you.
This is the problem:
ThanglishToTamilGUI tt = new ThanglishToTamilGUI();
String apper = tt.anz;
How do you expect apper to ever be anything other than null? You're fetching the variable from a freshly-created form, which has never been shown, and which has never had btnConvertToBraille_Click called on it.
Presumably there's an existing ThanglishToTamilGUI object somewhere, and that's the one you want to fetch the variable from. Basically, one form needs to know about the instance of the other form.
(I'd also strongly suggest using a property rather than a public variable, but that's a different matter. You might not even need to have a separate variable at all - just declare a property which fetches richTextBoxTamil.Text.)
Alternatively, just pass the relevant string to the constructor of the new form:
public void btnConvertToBraille_Click(object sender, EventArgs e)
{
GUI.TamilToBrailleGUI c1 = new GUI.TamilToBrailleGUI(richTextBoxTamil.Text);
c1.Visible = true;
}
Then the new form doesn't need to know about the old form at all - it only needs to know the text to display.
(You might want to pull it out of the constructor and into a settable property, but it's the same basically principle: the code creating the form pushes the data, rather than the new form pulling it.)
You can create a public property to access the current Text value of the textbox.
public string RichTextBoxText
{
get
{
return richTextBoxTamil.Text;
}
}
The way you do it now the form is instantiated, but the click event is not fired. So there's no way you will get anything other than what you initialized the field to.
Load is not the place to look for user input. An event (like click) is where you need to check the property value:
private void SomeClick(object sender, EventArgs e)
{
String result = thanglishToTamilGUIObject.RichTextBoxText;
//do something with text
}

Categories