Set child form image from parent form? - c#

So I am making some achievement pop ups for a lame game and so I made a custom messagebox form and I have been successful in setting the popups picturebox image with local images but I need help using embedded resources as images.
So far Ive used constructors to set the images and string but I can't use them for embedded images.
Parent Form:
MessageForm MsgFrm = new MessageForm
{
AchievementString = "L33t H4x0r - Reach 1337 score.",
PictureString = "C:\\Users\\Resources\\H4x0r_50x50.jpg"
};
MsgFrm.Show();
Child Form:
public string Achstring { get; set; }
public string Picstring { get; set; }
private void MessageForm_Load(object sender, EventArgs e)
{
achievement_lbl.Text = AchievementString;
achievement_pic.Image = Image.FromFile(PictureString);
}
Using the code above I can only use local images and my goal is to use images embedded in resources but to pass them as an arg of sorts as above.

You should either pass the Image object to a constructor or declare an Image property to set.
public MessageForm(Image img)
{
InitializeComponent();
achievement_pic.Image = img;
}
Or
Parent form
MessageForm MsgFrm = new MessageForm
{
AchievementString = "L33t H4x0r - Reach 1337 score.",
PictureImg = embeddedPicture
};
MsgFrm.Show();
Child form
public string Achstring { get; set; }
public Image PicImage { get; set; }
private void MessageForm_Load(object sender, EventArgs e)
{
achievement_lbl.Text = AchievementString;
achievement_pic.Image = PicImage
}
If you need more control in the parent form, you could make the control public or create a public property for the image.
public Control PicControl => achievement_pic;

Related

How to add to a List and display images from Resource File

I am creating a BlackJack game and I'm currently having a problem displaying the card image needed on my list.
I have added all 52 card to my resource file and I can't seem to have them displayed in a PictureBox.
Am I going about the right way?
My Card class:
internal class Card
{
public int Value { get; set; }
public string Name { get; set; }
public string Image { get; set; }
public Card(int value, string name, string image)
{
Value = value;
Name = name;
Image = image;
}
}
Main Form:
public partial class Form1 : Form
{
static List<Card> myListOfCards = new List<Card>();
static List<Card> dealersHand = new List<Card>();
static List<Card> playersHand = new List<Card>();
private void startButton_Click(object sender, EventArgs e)
{
//Clubs
myListOfCards.Add(new Card(2, "Two of Clubs", "Resources._2C.png"));
}
}
I've spotted a potential issue. Your code uses "Resources._2C.png" as a literal, and the Card class deals with it as a string. One way or another an Image must be retrieved from the resources of the Assembly and I don't see any code that does that.
Try this change:
class Card
{
// METHOD 1
// CTor with Image
public Card(int value, string name, Image image)
{
Value = value;
Name = name;
Image = image;
}
// METHOD 2
// CTor with string
// The `BuildAction` property for the image files must
// be set to `EmbeddedResource` for this version to work.
public Card(int value, string name, string resource)
{
Value = value;
Name = name;
Image = Image.FromStream(
typeof(Card)
.Assembly
.GetManifestResourceStream(resource));
}
public int Value { get; }
public string Name { get; }
// Try making this an Image
public Image Image { get; }
}
In the MainForm:
The image can either be read from the Resource file by removing the quotes and the extension:
// METHOD 1
private void buttonCard1_Click(object sender, EventArgs e)
{
var card = new Card(1, "AceOfDiamonds", Resources.AceOfDiamonds);
pictureBox1.Image = card.Image;
}
OR if the string is used, it must be fully qualified:
// METHOD 2
private void buttonCard2_Click(object sender, EventArgs e)
{
// Get full names of available resources
Debug.WriteLine(
string.Join(
Environment.NewLine,
typeof(MainForm).Assembly.GetManifestResourceNames()));
var card = new Card(2, "EightOfSpades", "resources.Images.EightOfSpades.png");
pictureBox1.Image = card.Image;
}
Gets this in the PictureBox:
FYI: Here are the available embedded resources listed by the Debug.WriteLine:

How do I get a label in a form to display the values of a property

In my C# windows form I have 2 forms. I would like to display a collection of strings in a label on a form. When I debug I show the 2 elements in my array but they are not showing in the label I am passing it to. When I hover of toString the data is there but how to I pass it to sender so it will display in the label control I have on my form?
In the snippet of code below to data is in toString but how do I get it from there down to sender.ToString????
public AccountReport_cs(Func<string> toString)
{
this.toString = toString;
}
private void AccountReport_cs_Load(object sender, EventArgs e)
{
label1.Text = sender.ToString();
}
This is another piece of the code that will open form2 where the information should be displayed.
private void reportButton2_Start(object sender, EventArgs e)
{
AccountReport_cs accountReport = new AccountReport_cs(allTransactions.ToString);
accountReport.ShowDialog();
}
Here is the last piece of code and this will show how the data gets to EndOfMonth.
public class Transaction
{
public string EndOfMonth { get; set; }
}
public override List<Transaction> closeMonth()
{
var transactions = new List<Transaction>();
var endString = new Transaction();
endString.EndOfMonth = reportString;
transactions.Add(endString);
return transactions;
}
If you need to send information between forms, the best thing you can do is create a property in the target form and assign the value you want to send before displaying the form; thus you will not need to change the default constructor of the form.
// Destiny form
public partial class FormDestiny : Form {
// Property for receive data from other forms, you decide the datatype
public string ExternalData { get; set; }
public FormDestiny() {
InitializeComponent();
// Set external data after InitializeComponent()
this.MyLabel.Text = ExternalData;
}
}
// Source form. Here, prepare all data to send to destiny form
public partial class FormSource : Form {
public FormSource() {
InitializeComponent();
}
private void SenderButton_Click(object sender, EventArgs e) {
// Instance of destiny form
FormDestiny destinyForm = new FormDestiny();
destinyForm.ExternalData = PrepareExternalData("someValueIfNeeded");
destinyForm.ShowDialog();
}
// Your business logic here
private string PrepareExternalData(string myparameters) {
string result = "";
// Some beautiful and complex code...
return result;
}
}

How to make my main WinForm update when another closes?

There's a duplicate post but the question was not answered.
My question is if a new form is created within a main form
var editor = new Edit(itemList, itemListBox);
editor.Show();
and the type of data you edit is:
Dictionary<int, Item>
Item is below:
public class Item
{
public string #Url { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Item(string #url, string name, double price)
{
this.Url = url;
this.Name = name;
this.Price = price;
}
public override string ToString()
{
return this.Name;
}
}
How can i add a handler for when editor is closed so it can update the ListBox in the main windows form.
Either add an eventhandler for the Form.Closed event
var editor = new Edit(itemList, itemListBox);
editor.Closed += OnEditorClosed(); // your eventhandler here
editor.Show();
or simply create modal dialog by using ShowDialog instead of Show
var editor = new Edit(itemList, itemListBox);
editor.ShowDialog(); // execution will stop here until editor is closed
Form has event handlers FormClosing and FormClosed. I think it'll be better to use the first one, since in the second the form's data may be alrready disposed. So:
editor.FormClosing += new FormClosingEventHandler(editor_FormClosing);
private void editor_FormClosing(object sender, FormClosingEventArgs e)
{
Edit editor = (Edit)sender;
// update data on main form here
}

How get determined buttons from class

this is not long story!! just it seems to be long ;)
in my app I have user access, it means access to a button relate to its user access scope.
in winform layer: I have a form, it shows all of the determined buttons' name in partitioned checkedListboxes. I dont want fill the form manually. I want create checkedListboxes by code. to get their items'text, I have below planing:
clssMenu_Item: I can save name and text property of one button in this class.
public class clssMenu_Item
{
public string name;
public string text;
}
clssMenu_List: it give me 2D generic List<clssMenu_Item>. all of the buttons in one form will be in a object of this class.
public class clssMenu_List
{
public clssMenu_List ()
{
// I dont know how fill private variables
}
#region private variables
private List<clssMenu_Item> _main ; // buttons in main form
private List<clssMenu_Item> _accountancy; //buttons in accountancy form
private List<clssMenu_Item> _management; //buttons in management form
#endregion
#region public properties
public List<clssMenu_Item> main
{ get { return _main; } }
public List<clssMenu_Item> accountancy
{ get { return _accountancy; } }
public List<clssMenu_Item> management
{ get { return _management; } }
#endregion
}
the buttons in each forms have a common character in their Name property. For example all of the determined buttons in Main form are started with ''Mbtn'', so there isn't any same buttons' Name between forms.
now I dont know how fill private variables in clssMenu_List. then I could use it in my facade layer.
thanks for your attention my friend!! please help me to solve it
I would create a separated helper class that extracts all buttons from a form.
public static class FormHelper
{
public static Button[] GetButtonsFromForm(Form form)
{
// ...
}
}
I would create properties instead of fields:
public class clssMenu_Item
{
public string Name {get;set;}
public string Text {get;set;}
}
A method to create menu_items:
public IEnumerable<clssMenu_Item> GetMenuItemsFromForm(Form form)
{
// convert the buttons to menu_items
return from button in FormHelper.GetButtonsFromForm(form);
select new clssMenu_Item { Name = button.Name, Text = button.Text };
}
Next I would add all buttons to the right list.
public void Fill()
{
clssMenu_List lst = new clssMenu_List();
clssMenu_List.main.AddRange(GetMenuItemsFromForm(mainForm));
clssMenu_List.accountancy.AddRange(GetMenuItemsFromForm(accountancyForm));
clssMenu_List.management.AddRange(GetMenuItemsFromForm(managementForm));
}
Don't forget to create the list in you class:
private List<clssMenu_Item> _main = new List<classMenu_Item>(); // buttons in main form
private List<clssMenu_Item> _accountancy = new List<classMenu_Item>(); //buttons in accountancy form
private List<clssMenu_Item> _management = new List<classMenu_Item>(); //buttons in management form
Personally:
I would store them in a dictionary because you can access them by name. And I would not create properties of List-types. I'd rather create Add/Remove methods.

Need some guide on simple undo/redo

This is my first C# application, entirely self-taught without any prior software programming background. I did some research on Undo/Redo but could not find anything helpful (or easy to understand). Therefore, I'm hoping someone can help me in designing undo/redo function for my program (winforms application). The application consist of a main form where subsequent child forms will be called to record user specified values during certain events (button clicks etc). After every event is handled, a bitmap will be drawn in buffer and then loaded to a picturebox within the main form during the OnPaint event of the main form. Each input in separated into custom class objects and added into separate List and BindingList. Objects contained within List are used for graphics (to indicate coordinates etc) while objects in BindingList are used to display some important values on DataGridView. Just to give a brief description, the codes look something like this:
public partial class MainForm : form
{
public class DataClass_1
{
public double a { get; set; }
public double b { get; set; }
public SubDataClass_1 { get; set; }
}
public class SubDataClass_1
{
public double x { get; set; }
public double y { get; set; }
public string SomeString { get; set; }
public CustomEnum Enum_SubDataClass_1 { get; set; }
}
public class DisplayDataClass
{
public string SomeString { get; set; }
public double e { get; set; }
public double f { get; set; }
}
public enum CustomEnum { Enum1, Enum2, Enum3 };
// Lists that contain objects which hold the necessary values to be drawn and displayed
public List<DataClass_1> List_1 = new List<DataClass_1>();
public List<DataClass_2> List_2 = new List<DataClass_2>(); // Object has similar data types as DataClass_1
public BindingList<DisplayDataClass> DisplayList = new BindingList<DisplayDataClass>();
Bitmap buffer;
public MainForm()
{
InitializeComponent();
dgv.DataSource = DisplayList;
}
private void DrawObject_1()
{
// some drawing codes here
}
private void DrawObject_2()
{
// some drawing codes here
}
protected override void OnPaint(PaintEventArgs e)
{
DrawObject_1();
DrawObject_2();
pictureBox1.Image = buffer;
}
// Event to get input
private void action_button_click(object sender, EventArgs e)
{
ChildForm form = new ChildForm(this);
form.ShowDialog();
Invalidate();
}
}
The child forms' codes look something like this:
public partial class ChildForm : form
{
public ChildForm(MainForm MainForm)
{
InitializeComponent();
// Do something
}
private void ok_button_click(object sender, EventArgs e)
{
DataClass_1 Data_1 = new DataClass_1();
DisplayDataClass DisplayData = new DisplayDataClass();
// Parsing, calculations, set values to Data_1 and DisplayData
MainForm.List_1.Add(Data_1);
MainForm.DisplayList.Add(DisplayData);
this.DialogResult = System.Windows.Forms.DialogResult.OK;
this.Close();
}
}
Since all necessary data are stored in the lists and will only be changed after certain events are triggered (mostly button clicks), therefore I tried to use these lists to determine the state of the application during run time. My approach in implementing the undo/redo function is by adding the following codes:
public partial class MainForm : form
{
public class State()
{
public List<DataClass_1> List_1 { get; set; }
public List<DataClass_2> List_2 { get; set; }
public BindingList<DisplayDataClass> DisplayList { get; set; }
// and so on
public State()
{
List_1 = new List<DataClass_1>();
List_2 = new List<DataClass_2>();
DisplayList = new BindingList<DisplayDataClass>();
}
}
State currentState = new State();
Stack<State> undoStack = new Stack<State>();
Stack<State> redoStack = new Stack<State>();
private void MainForm_Shown(object sender, EventArgs e)
{
// Saves original state as first item in undoStack
undoStack.Push(currentState);
}
protected override void OnPaint(PaintEventArgs e)
{
// Update lists from currentState before drawing
List_1 = new List<DataClass_1>(currentState.List_1);
List_2 = new List<DataClass_2>(currentState.List_2);
DisplayList = new BindingList<DisplayDataClass>(currentState.DisplayList);
}
// When undo button is clicked
private void undo_button_Click(object sender, EventArgs e)
{
if (undoStack.Count > 0)
{
redoStack.Push(currentState);
undoStack.Pop();
currentState = undoStack.Last();
Invalidate();
}
}
// When redo button is clicked
private void redo_button_Click(object sender, EventArgs e)
{
// Have not thought about this yet, trying to get undo done first
}
// Events that trigger changes to values held by data objects
private void action_button_Click(object sender, EventArgs e)
{
// Replace the following code with previously stated version
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
ChildForm form = new ChildForm(this)
UpdateState();
undoStack.Push(currentState);
Invalidate();
}
}
// To update currentState to current values
private void UpdateState()
{
currentState.List_1 = new List<DataClass_1>(List_1);
currentState.List_2 = new List<DataClass_2>(List_2);
currentState.DisplayList = new BindingList<DisplayDataClass>(DisplayList);
// and so on
}
}
Result:
The application does not perform the undo function correctly. The program shows the correct output under normal conditions but when the undo event is triggered, regardless of how many objects have been drawn, the application reverts back to initial state (the state where there is no recorded data). I've used System.Diagnostics.Debug.WriteLine() during events where the stack is changed to check the number of counts within undoStack and it seems to give the correct counts. I'm guessing that the lists need to be copied/cloned in a different manner? Or am I doing something wrong here? Can anyone please guide me? Performance, readability, resource management, future maintenance and etc need not be considered.
There are a lot of approaches that will work, each with different strengths and weaknesses, but I generally like to define an abstract Action class and then a separate UndoRedoStack class.
The Action class would have two methods (Do and Undo) which each subclassed Action can implement. You isolate any logic that can "change state" to these Action subclasses thereby keeping that logic neatly encapsulated.
The UndoRedoStack is like a regular stack except with three core methods.
ApplyAction (like Push)
UndoAction (like Pop, but be sure to only
move the pointer/index without truncating or throwing away any
existing actions).
RedoAction (like Push, but you use the next value
already in the underlying stack/list instead of pushping/inserting a
new one).
Usually I find the biggest challenge then becomes designing each Action subclass in such a way that it maintains enough information to both undo and redo itself. But being able to encapsulate all state manipulation logic to individual Action subclasses usually makes it easiest for me to maintain in the long run.
You are storing reference objects in your stacks. If you want your method to work, you need to implement a clone() method in your state object, and store a new clone each time, otherwise, changes made are made to each member of the stack, as they all point to the same reference object.

Categories

Resources