I'm currently writing a function that creates button in XAML (on runtime) according to JSON information that is received from an API call in C#.
I currently have the following code:
Button downloadButton = new Button();
downloadButton.Click += new RoutedEventHandler(DownloadContent);
But I get the following error:
An object reference is required for the non-static field, method, or
property 'Mainwindow.DownloadContent(object, RoutedEventArgs)'
I've tried changing it to downloadButton.Click += new RoutedEventHandler(this, DownloadContent); but that gives me the error:
Keyword 'this' is not valid in a static property, static method, or static field initializer
For reference this is what DownloadContent looks like
private void DownloadContent(object sender, RoutedEventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri("API-URL"), contentZip);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(InstallContent);
}
This is what I want the button to look like (skipping the other stuff like background color, etc.)
<Button Name="Downloadbutton"
Content="Download"
Click="DownloadContent"
</Button>
Am I missing something as why I get this Error and how could I fix it?
EDIT
The Installcontent function looks like this:
private void InstallContent(object sender, AsyncCompletedEventArgs e)
{
ZipFile.ExtractToDirectory(contentZip, contentPath, true);
File.Delete(contentZip);
writeJsonData(DLCbuttonTag);
Downloadbutton.Visibility = Visibility.Collapsed;
Uninstallbutton.Visibility = Visibility.Visible;
}
The function that creates the button:
public static void getContentList()
{
string jsonString = File.ReadAllText(#"C:\Users\stage\OneDrive\Documenten\ContentInfo.json")
ContentList contentList = JsonConvert.DeserializeObject<ContentList>(jsonString);;
for (int i = 0; i < contentList.Content.Count; i++)
{
StackPanel dynamicStackPanel = new StackPanel();
dynamicStackPanel.Orientation = Orientation.Horizontal;
dynamicStackPanel.Background = Brushes.Transparent;
Button downloadButton = new Button();
downloadButton.Click += new RoutedEventHandler(DownloadContent);
dynamicStackPanel.Children.Add(downloadButton);
}
}
The problem is that getContentList is declared as static. You try to reference the method DownloadContent which is an instance method. Remove the static from getContentList to fix the error.
The reason for the error is that static methods cannot access instance members. Static members do not run in the context of a particular instance, but in the context of the type itself. While in the case of WPF there most likely is no other instance of your page, in theory there could be many. The static method would not know which instance to pick, hence the error.
See this link for details on static members.
As a sidenote: in C#, methods are usually started with a capital letter (Pascal casing) regardless of their access modifier. So getContentList would be GetContentList.
Related
I'm trying to pass file in FileChooser in Gtk# and them using second button read from this file. I can't pass FileChooser to function, which is triggered when second button is clicked.
namespace SharpTest{
internal static class SharpTest{
public static void Main(string[] args){
Application.Init();
var window = new Window("Sharp Test");
window.Resize(600, 400);
window.DeleteEvent += Window_Delete;
var fileButton = new FileChooserButton("Choose file", FileChooserAction.Open);
var scanButton = new Button("Scan file");
scanButton.SetSizeRequest(100, 50);
scanButton.Clicked += ScanFile;
var boxMain = new VBox();
boxMain.PackStart(fileButton, false, false, 5);
boxMain.PackStart(scanButton, false, false, 100);
window.Add(boxMain);
window.ShowAll();
Application.Run();
}
private static void Window_Delete(object o, DeleteEventArgs args){
Application.Quit ();
args.RetVal = true;
}
private static void ScanFile(object sender, EventArgs eventArgs){
//Read from file
}
}
}
The FileName property in FileChooserButton scanButton holds the name of the file chosen. The problem you face is that you cannot access the button from ScanFile(), since it is outside Main(), and scanButton is a local reference inside it.
Also, you are using an old-style fashion of creating event handlers. You can actually use lambdas for that purpose (the easiest option), and modify the parameters in the call to ScanFile() the way you like.
So, instead of:
scanButton.Clicked += ScanFile;
you can change it for:
scanButton.Clicked += (obj, evt) => ScanFile( fileButton.Filename );
which will do the trick, provided that you change ScanFile() to be:
private static void ScanFile(string fn)
{
// ... do something with the file name in fn...
}
With that lambda, you are creating an anonymous function that accepts an object obj (the sender of the event), and an EventArgs args object (the arguments of the event). You are doing nothing with that info, so you dismiss it, since you're just interested in the value of the FileName property in scanButton.
Hope this helps.
Ok so I'm attempting to create a simple game. In a nutshell it's a resource management game where the player will attempt to manage a thieves guild. In regards to running missions I've created a Thief class, a new instance of which is created when a new thief is recruited. I have coded within the thief class the ability to gain experience and level up.
Here's my specific problem:
I want the player to be able to select which thief/thieves to send on a mission. I have thought about it and figured that opening a new form and populating it with checkboxes is the easiest way to allow this. These checkboxes will be related to a List<thief> of thieves, the player then checks the thieves s/he wants to send and these are then stored in another List<thief> and passed on to the run mission function.
I've built a separate project with the intention of testing and playing around with this before putting it into the main program. The test project consists of two forms: The first (frmMain) with a textbox to hold the selected options and a button to open the second form (frmSelect). Currently I can open and populate the second form (frmSelect) but when I try to add the checked options to the textbox I simply...well can't.
So far I have tried directly accessing the textbox by typing frmMain.txtOptionsDisplay in the cs file of frmSelect but it causes the following error:
An object reference is required for the non-static field, method or
property
I tried to create a new form in frmSelect and make it equal to the active instance of frmMain with: Form frmTemp = frmMain.ActiveForm; and then alter the textbox using frmTemp as a go-between but that produced the error:
'System.Windows.Forms.Form' does not contain a definition for
'txtOptionsDisplay'.
Having searched both google and stackoverflow forums I've encountered answers that I either have never heard of (Threading) or answers that I kind've recognise but can't interpret the code pasted to make it relevant to my problem (delegates).
Any advice or pointers would be fantastic.
EDIT:
frmMain code:
public frmMain()
{
InitializeComponent();
selections.Add("Option 1");
selections.Add("Option 2");
}
private void btnClick_Click(object sender, EventArgs e)
{
frmSelectOptions.Show();
int length = selections.Count();
for (int i = 0; i < length; i++)
{
CheckBox box = new CheckBox();
box.Text = selections[i];
box.AutoSize = true;
box.Location = new Point(50, 50*(i+1));
frmSelectOptions.grpControls.Controls.Add(box);
}
}
public void updateText(string option)
{
txtOptionsDisplay.Text += option;
}
}
frmSelect code:
public List<CheckBox> selectedOptions = new List<CheckBox>();
Form frmTemp = frmMain.ActiveForm;
public frmSelect()
{
InitializeComponent();
}
private void btnSelect_Click(object sender, EventArgs e)
{
foreach (CheckBox box in grpControls.Controls)
{
if (box.Checked == true)
selectedOptions.Add(box);
}
this.Hide();
}
}
I hope this formats correctly... I'm kinda new and don't know how to indent. Oh look there's a preview...
Does this help?
Your problem is that controls defined within a form by default receive the private access identifier. Hence you could just add a property along the lines of
public ControlType ProxyProperty {
get {
return txtOptionsDisplay;
}
}
Besides from that you should think about wether what you're trying is actually a good solution. Manipulating forms from one to another will become a huge clusterfuck in terms of maintenance later on.
I'd suggest using the Singleton pattern for your frmMain. This will help safeguard you from accidentally launching another instance of frmMain and at the same time, will give you access to frmMain's objects. From there, you can either write accessors to Get your txtOptionsDisplay or you can make it public. Below is an example:
public class frmMain
{
private static frmMain Instance = null;
private static object LockObj = new object();
public static frmMain GetMain()
{
// Thread-safe singleton
lock(LockObj)
{
if(Instance == null)
Instance = new frmMain();
return Instance;
}
}
public string GetOptionsDisplayText()
{
return txtOptionsDisplay.Text;
}
}
public class frmSelect
{
private void frmSelect_Load(object sender, EventArgs e)
{
// Set whatever text you want to frmMain's txtOptionsDisplay text
txtDisplay.Text = frmMain.GetMain().GetOptionsDisplayText();
}
}
If you do go this route, don't forget to update Program.cs to use frmMain's singleton.
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new frmMain()); - Old method
Application.Run(frmMain.GetMain());
}
I created a class and I want to use the constructor of the class Rtb(),
public class Rtb
{
public RichTextBox newRTB;
public Rtb()
{
newRTB = new RichTextBox();
newRTB.IsReadOnly = true;
newRTB.MouseDoubleClick += new MouseButtonEventHandler(newRTB_MouseDoubleClick);
}
private void newRTB_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
.....
}
}
In below code, i created an object of Rtb(),but this object can not assigned to newBUC.Child, an error after run: Cannot implicitly convert type 'WpfApplication1.Rtb' to 'System.Windows.UIElement'
private void menu_Click(object sender, RoutedEventArgs e)
{
BlockUIContainer newBUC = new BlockUIContainer();
newBUC.Margin = new Thickness(50, 10, 50, 10);
mainMenu.Document.Blocks.Add(newBUC);
Rtb newnew = new Rtb();
newBUC.Child = newnew;
}
I tried to use to cast it, and use "as", like below, but it did not work. I think probably i need the right type to perform the assignment, how should i do?
newBUC.Child = newnew as BlockUIContainer;
newBUC.Child = (BlockUIContainer) newnew;
You can't add newnew as a Child, because you class does not inherit from UIElement. But what can you do is set Child to underlying RichTextBox called newRTB which inherits from UIElement
newBUC.Child = newnew.newRTB;
In my case I was missing a reference to PresentationFramework.dll
located on Program files* x86( reference assembles„Microsoft\FRamewrk\3.0\
or your FRamework version
This got me access to all dependencies on my XAML Partial class and therefore able to resolve
I hope this also can help on your coding, It worked for me.
In my program I am creating PictureBoxes which move across the screen. I want to make it so that the user can create as many of these as they want. To do this I created a class is assigned to a picturebox after it is created and controls it's movement. This works for the picturebox until I create another one, when it is no longer controlled. I assume this is because c# does not allow me to create multiple objects of a class, and therefore ends the previous ones to make a new one. Here's how I've done it:
static ArrayList cps = new ArrayList();
public void ShootCannon() {
Image cubeImage= Image.FromFile("C:\\Users\\Stefan\\Documents\\Visual Studio 2010\\Projects\\Game1\\Game1\\Resources\\CannonCube.png");
PictureBox cannonCube = new PictureBox();
ScreenPanel.Controls.Add(cannonCube);
cannonCube.Image = cubeImage;
cannonCube.SetBounds(cannonCubeInst.X, cannonCubeInst.Y, cubeImage.Width, cubeImage.Height);
cannonCube.BringToFront();
cps.Add(new CubeProjectile(cannonCube));
}
And the CubeProjectile class is:
public class CubeProjectile
{
static PictureBox box;
public CubeProjectile(PictureBox box1)
{
box = box1;
Timer Update = new Timer();
Update.Interval = 1;
Update.Tick += new EventHandler(Timer_Tick);
Update.Start();
}
void Timer_Tick(object sender, EventArgs e)
{
Point loc = new Point(box.Location.X, box.Location.Y);
box.SetBounds(loc.X + 1, loc.Y, box.Width, box.Height);
}
}
You can create how many instances of a class you want.
The problem is that you are using a static variable inside the class. That only exists once, no matter how many instances you create. When you create the second instance it will overwrite the value in the static variable with the new picture box.
You need an instance variable to hold one picture bx per instance of the class.
Change this:
static PictureBox box;
to:
PictureBox box;
Side note: A good practice is to specify the access level for members of the class, and only make those public that you want to access from outside the class. Making your member variable private makes sure that it's only accessed from that instance:
private PictureBox box;
A static variable declared in a class is common to all instances of that class. So your PictureBox box is overwritten with the latest picturebox that you pass to the constructor of your class
So if you use your code above and call
CubeProjectile cb1 = new CubeProjectile(pic1);
CubeProjectile cb2 = new CubeProjectile(pic2);
both instances of CubeProjectile share the latest picturebox passed to the constructor pic2
Instead if you declare the variable without the static modifier, every instance of the class has its own PictureBox
public class CubeProjectile
{
private PictureBox box;
public CubeProjectile(PictureBox box1)
{
box = box1;
Timer Update = new Timer();
Update.Interval = 1;
Update.Tick += new EventHandler(Timer_Tick);
Update.Start();
}
void Timer_Tick(object sender, EventArgs e)
{
Point loc = new Point(box.Location.X, box.Location.Y);
box.SetBounds(loc.X + 1, loc.Y, box.Width, box.Height);
}
}
CubeProjectile cb1 = new CubeProjectile(pic1);
CubeProjectile cb2 = new CubeProjectile(pic2);
Now cb1 has the reference to pic1 stored in the internal variable box and cb2 references the pic2
However, keep in mind that a PictureBox is the host of a possible expensive resource (The Image property) and you should be sure to dispose these instances of CubeProjectile when no more needed
Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers