I got two scenes (windows), "MainWindow.xaml.cs" and "SecondaryWindow.xaml.cs". I also have one class "Control.cs".
Im trying to declare 2 different List<string>, and 2 public string in my Control.cs class.
It looks like this.
class Control
{
}
public class MyControl
{
List<string> NameList = new List<string>();
List<string> DescriptionList = new List<string>();
public string Name {
get { return Name; }
set { Name = value; }
}
public string Description {
get { return Description; }
set { Description = value; }
}
}
I want to access the different strings from Control.cs in my SecondWindow.xaml.cs class so that i can give them each a value from 2 textboxes in SecondWindow.
After this i want the string Name to save to NameList and string Description to DescriptionList.
Then I will send Name to a ListBox in "MainWindow" where i think it could be added something like this..?
private void Button_SaveAndReturn(object sender, RoutedEventArgs e)
{
var main = (MainWindow)Application.Current.MainWindow;
if (Example.Name != "" && Example.Description != "")
{
DateTime now = DateTime.Now;
main.listBox.Items.Add(string.Format("{0}: {1} ", Example.name, now));
this.Close();
}
Im trying my best to give out as much details as i can, tell me if there is anything else you need! Thanks in advance.
Edit
Here is my Control class:
class Control
{
List<string> NameList = new List<string>();
List<string> DescriptionList = new List<string>();
public static string Name
{
get { return Name; }
set { Name = value; }
}
public static string Description
{
get { return Description; }
set { Description = value; }
}
}
And my main class
private void Button_SaveAndReturn(object sender, RoutedEventArgs e)
{
List<string> nameList = new List<string>();
List<string> descriptionList = new List<string>();
var name = Control.Name;
var desc = Control.Description;
var main = (MainWindow)Application.Current.MainWindow;
if (name != "" && desc !="")
{
nameList.Add(name);
descriptionList.Add(desc);
DateTime now = DateTime.Now;
main.listBox.Items.Add(string.Format("{0}: {1} ", name, now));
this.Close();
}
else if (name== "")
{
MessageBox.Show("Please enter a name", "Name Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.NameInput.Focus();
}
else
{
MessageBox.Show("Please enter some text", "Text Error", MessageBoxButton.OK, MessageBoxImage.Error);
this.TextInput.Focus();
}
Are you using WPF's MVVM capabilities? If you are, you can declare those lists and variables in a viewmodel common to all those classes; otherwise just mark all those properties as static so you can access them from the other classes like: MyControl.Name, MyControl.Description, etc...
I would use Prism for that.
Here is an example:
Class which will raise the event:
public class PublisherClass
{
public void UpdateName(string name)
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Publish(name);
}
}
Two classes will subscribe to this event:
public class SubscriberClass1
{
public string Name { get; set; }
public SubscriberClass1()
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
}
private void UpdateName(string name)
{
this.Name = name;
}
}
and
public class SubscriberClass2
{
public string Name { get; set; }
public SubscriberClass2()
{
Utility.EventAggregator.GetEvent<UpdateNameEvent>().Subscribe(UpdateName);
}
private void UpdateName(string name)
{
this.Name = name;
}
}
EventAggregator which is part of Prism.Events resides here:
public class Utility
{
public static EventAggregator EventAggregator { get; set; }
static Utility()
{
EventAggregator = new EventAggregator();
}
}
And the event is simply defined like this:
public class UpdateNameEvent : PubSubEvent<string>
{
}
Now give it a try:
static void Main(string[] args)
{
PublisherClass publisher = new PublisherClass();
SubscriberClass1 subscriber1 = new SubscriberClass1();
SubscriberClass2 subscriber2 = new SubscriberClass2();
publisher.UpdateName("Name1");
Console.WriteLine(subscriber1.Name);
Console.WriteLine(subscriber2.Name);
}
For this example i am using a string as parameter but you can replace that according to your needs.
Be it an MVVM approach or any other pattern, you can easily implement this kind of communication.
Install Prism.Core with the help of Nuget and you will get the reference to Prism dll.
That's about it.
Related
I need some homework help, I have a bunch of interfaces that implement credit card forms. How can I pass a value entered into a form (like a textbox entry) by a user to a class that implemented the interfaces?
The interface code is below
public interface IInfoCard
{
string Name { get; set; }
string Category { get; }
string GetDataAsString();
void DisplayData(Panel displayPanel);
void CloseDisplay();
bool EditData();
}
public interface IInfoCardFactory
{
IInfoCard CreateNewInfoCard(string category);
IInfoCard CreateInfoCard(string initialDetails);
string[] CategoriesSupported { get; }
string GetDescription(string category);
}
I created a new class that implements those interfaces. The interface implements my form but the instructor hid that code from us.
Here is the class code that implemented the above two interfaces.
internal class CreditCardInfo : IInfoCardFactory,IInfoCard
{
private string[] categories = new string[] { "Credit Card" };
private string name;
public string[] CategoriesSupported
{
get { return categories; }
set { categories = value; }
}
public string Name { get
{
return this.name;
}
set { this.name = value; }
}
public string Category
{
get
{
return this.categories[0];
}
set
{
this.categories[0] = value;
}
}
public void CloseDisplay()
{
throw new NotImplementedException();
}
public IInfoCard CreateInfoCard(string initialDetails)
{
string[] stringToSplit = initialDetails.Split(new char[] { '|' });
string category = stringToSplit[0];
string description = stringToSplit[1];
return new CreditCardInfo();
}
public IInfoCard CreateNewInfoCard(string category)
{
return new CreditCardInfo();
}
public void DisplayData(Panel displayPanel)
{
string data = this.Name + "\n" + this.Category;
//add a label and concatenate to the data
Label label = new Label();
label.Text = data;
//add the label to the panel
displayPanel.Controls.Add(label);
}
public bool EditData()
{
//show the form to edit the credit card information
//start add credit card info with the fields
CreditCardForm creditCardForm = new CreditCardForm();
creditCardForm.Name = this.Name;
//get the fields and add the values to them
creditCardForm.ShowDialog();
return true;
}
public string GetDataAsString()
{
//I need help here getting the data as string
return "Data";
}
public string GetDescription(string category)
{
return "Save personal info about your credit card";
}
}
The section where I have commented I need help is where am stuck, That method is supposed to return all the data entered into the CreditCard info fields as a single string. Since the forms were implemented through the interfaces, how do I pass the data from the form to the class method GetDataAsString()?
It looks like you need to determine if the dialog result is true, which then calls the GetDataAsString() method.
You may also need some PropertyChanged events, to assign the data from the form to the properties, but I’m not sure entirely, as I’m not at my computer atm.
To get the properties into 1 string, you will need to do something like this
var string = property1.ToString();
string += property2.ToString();
For a project i am working with intherentance and an abstract class. with the help of a form i want to add items into a list, but get the following error during coding: cannot create an instance abstract type or interface 'Article'. does someone know how to fixt his?
articlemanager class:
private List<Article> items;
public ArticleManager()
{
items = new List<Article>();
}
public void addArticleEmergency(Article emergencyNews)
{
items.Add(emergencyNews);
}
abstract article class:
abstract class Article
{
public int id { get; private set; }
public string title { get; private set; }
public string text { get; private set; }
public Article(int id, string title, string text)
{
this.id = id;
this.title = title;
this.text = text;
}
public bool HasID(int id)
{
if (id == this.id)
{
return true;
}
return false;
}
public override string ToString()
{
return id + ": \r\n" + title + " \r\n " + text;
}
}
}
form:
private ArticleManager articalManagerAdd;
public Form1()
{
InitializeComponent();
this.articalManagerAdd = new ArticleManager();
}
private void btnMakeNewsArticle_Click(object sender, EventArgs e)
{
if(txtNewsNumber.Text == "" || txtNewsTitle.Text == "" || txtNewsText.Text == "" || !rbEmergency.Checked && !rbNormal.Checked )
{
lbSeeNewsItem.Items.Clear();
lbSeeNewsItem.Items.Add("Please fill in all the required information");
}
else
{
if (articalManagerAdd.GetArticle(Convert.ToInt32(txtNewsNumber.Text)) == null)
{
if (rbNormal.Checked)
{
articalManagerAdd.addArticleNormal(new Article(Convert.ToInt32(txtNewsNumber.Text), txtNewsTitle.Text, txtNewsText.Text));
MessageBox.Show("Normal news article has been added");
}
else if(rbEmergency.Checked)
{
Article emergencyNews = new NewsArticle(Convert.ToInt32(txtNewsNumber.Text), txtNewsTitle.Text, txtNewsText.Text);
MessageBox.Show("Emergency news article has been added");
}
}
else
{
lbSeeNewsItem.Items.Add("This id has already been used");
}
}
}
As the comments have mentioned, you cannot create an instance of an abstract class.
So your code new Article(Convert.ToInt32(txtNewsNumber.Text), txtNewsTitle.Text, txtNewsText.Text)) will not compile.
You can inherit from a non-abstract class so your NewsArticle class would be expected to work if you just removed the abstract modifier to your Article class.
Alternatively you could add a new sub-class of Article say NormalArticle and use that in your addArticleNormal method
My code's purpose is to change my 'dispatcher' object's name and whilst this is done through the dispatcher's name property's setter, it runs OnNameChange() where I raise the event.
This is where I want the "OnDispatcherNameChange" method to be run where it displays a message ("Dispatcher's name changed to ").
However, when I run the main, and enter a name, it returns a StackOverFlowException. How can I fix this?
This is my code:
using System;
namespace Excercise_Events
{
public class NameChangeEventArgs : EventArgs
{
public string Name { get; private set; }
public NameChangeEventArgs(string name)
{
this.Name = name;
}
}
public class Dispatcher
{
public string Name
{
get
{
return Name;
}
set
{
var nameChange = new NameChangeEventArgs(Name);
OnNameChange(nameChange);
Name = value;
}
}
public delegate void NameChangeEventHandler(object Source, NameChangeEventArgs args);
public event NameChangeEventHandler NameChange;
protected virtual void OnNameChange(NameChangeEventArgs args)
{
NameChange?.Invoke(this, new NameChangeEventArgs(args.Name));
}
}
public class Handler
{
public void OnDispatcherNameChange(object Source, NameChangeEventArgs args)
{
Console.WriteLine("Dispatcher's name changed to {0}", args.Name);
}
}
class Program
{
static void Main(string[] args)
{
var dispatcher = new Dispatcher();
var handler = new Handler();
dispatcher.NameChange += handler.OnDispatcherNameChange;
while (true)
{
Console.Write("Enter new Name: ");
string name = Console.ReadLine();
if (name.ToLower() == "end")
{
break;
}
dispatcher.Name = name;
}
}
}
}
The Name property is the problem. You have an infinite loop where the setter is calling the property again to set another value.
Change it to use a backing field:
private string _name;
public string Name
{
get
{
return _name;
}
set
{
var nameChange = new NameChangeEventArgs(Name);
OnNameChange(nameChange);
_name = value;
}
}
I'm still fairly new to programming, and have started a project where I'm trying to seperate functionality of the program into classes, where each class handles most everything related to that specific part of the program.
I have one class, called DirectoryMonitors, that creates an object that monitors a directory with FileSystemWatcher. I'm trying to add items to a ListBox on the MainForm from an instance of this DirectoryMonitors class. However, it seems I'm unable to call the method in MainForm unless it's static - but if it's static, I can't access my ListBox.
Relevant part of my DirectoryMonitor class:
public class DirectoryMonitorData
{
public bool WatcherActive { get; set; } = true;
public string EQVersion { get; set; }
public string FolderLocation { get; set; }
}
public class DirectoryMonitor : DirectoryMonitorData
{
private void FolderWatcher_Changed(object sender, FileSystemEventArgs e)
{
FileInfo fi = new FileInfo(e.FullPath);
if (!IsFileLocked(fi))
{
int startPos = e.FullPath.LastIndexOf("\\") + 1;
int endPos = e.FullPath.IndexOf("-Inventory") - startPos;
string character = e.FullPath.Substring(startPos, endPos);
MessageBox.Show(character);
string[] delimiters = { ControlChars.Tab.ToString() };
using (TextFieldParser parser = Microsoft.VisualBasic.FileIO.FileSystem.OpenTextFieldParser(e.FullPath, delimiters))
{
// Process the file's lines.
while (!parser.EndOfData)
{
try
{
string[] fields = parser.ReadFields();
MainForm.addLogToListBox(fields[0]);
for (int i = 1; i <= 5; i++)
{
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
private bool IsFileLocked(FileInfo file)
{
...
}
}
Relevant part of my MainForm class:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
public void addLogToListBox(string logMessage)
{
logsListBox.Items.Insert(0, logMessage);
}
}
UPDATED CODE:
public FileSystemWatcher FolderWatcher = new FileSystemWatcher();
public DirectoryMonitor()
{
FolderWatcher.NotifyFilter = NotifyFilters.LastWrite;
FolderWatcher.Filter = "*-Inventory.txt";
FolderWatcher.Changed += FolderWatcher_Changed;
}
public void setupDirectoryMonitorList()
{
foreach (DirectoryMonitorData dmd in MainForm.directoryMonitorList)
{
DirectoryMonitor dm = new DirectoryMonitor()
{
WatcherActive = dmd.WatcherActive,
FolderLocation = dmd.FolderLocation,
EQVersion = dmd.EQVersion
};
if (dm.WatcherActive)
{
dm.FolderWatcher.Path = dm.FolderLocation;
dm.FolderWatcher.EnableRaisingEvents = true;
dm.FolderWatcher.NotifyFilter = NotifyFilters.LastWrite;
dm.FolderWatcher.Filter = "*-Inventory.txt";
dm.FolderWatcher.Changed += FolderWatcher_Changed;
}
MainForm.directoryMonitorObjects.Add(dm);
}
}
Add a property to your DirectoryMonitorData class and pass list box to it:
public class DirectoryMonitorData
{
public bool WatcherActive { get; set; } = true;
public string EQVersion { get; set; }
public string FolderLocation { get; set; }
public ListBox Logs {get; set;}
}
and then:
DirectoryMonitor monitor = new DirectoryMonitor { Logs = logsListBox };
now in your class you can simply add anything to that listbox:
Logs.Items.Add(Something);
The way I normally do that is to add a constructor to the class, that takes a 'MainForm' parameter, then save the 'MainForm' parameter in a field.
public class DirectoryMonitor : DirectoryMonitorData
{
public DirectoryMonitor(MainForm form)
{
this.mainForm = form;
}
private MainForm mainForm;
}
Now you can access all public methods an properties of MainForm by using the field mainForm.
Alternative:
Create an eventhandler in your class (with a custom EventArgs). Then from your 'MainForm', subscribe to that event. Now the class does not have to know anything about the form. You just need to Invoke the eventhandler in your class.
I'm a student in a C# class and this is my introductory assignment to Classes, so please bear with me. When the New button is pressed, a CPerson object will be created using the name and phone values and the object will be added to a List<>.
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
}
public partial class Form1 : Form
{
private List<CPerson> PhoneNum = new List<CPerson>(); //<CPerson> or <string>?
public Form1()
{
InitializeComponent();
newbutton.Enabled = false;
changebutton.Enabled = false;
savebutton.Enabled = false;
}
private void newbutton_Click(object sender, EventArgs e)
{
changebutton.Enabled = true;
savebutton.Enabled = true;
PhoneNum.Add(new CPerson { Name = Namebox.Text + " : ", Phone = phonebox.Text });
listBox1.Items.Add(PhoneNum); //text = "Collection"
}
The assignment says "The CPerson ToString() override will be used to display the name and phone number in the listbox" as shown in the above image, which I don't necessarily understand, but I'm guessing I have to use something like this?
CPerson data = new CPerson();
data.ToString();
Either way, as the code is now, all I get in my listbox is "(Collection)". Any help would be appreciated!
That is asking to override the ToString() method. You can do it like this:
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
public override string ToString()
{
return Name + ": " + Phone;
}
I did not get right the part of adding to the list, but I assume you can do the following using ToString():
listBox1.Items.Add(data.ToString());
Close...
class CPerson
{
private string m_sName;
private string m_sPhone;
public string Name
{
get { return this.m_sName; }
set
{
this.m_sName = value;
}
}
public string Phone
{
get { return this.m_sPhone; }
set
{
this.m_sPhone = value;
}
}
public override string ToString()
{
return Name + ": " + Phone;
}
}
}