《命令与征服™:重制版》

《命令与征服™:重制版》

《命令与征服™》重制版合集工作坊
创建、共享和畅玩各种模组,尽情享受自定义的《命令与征服》游戏体验!还内含全新地图编辑器。欢迎回来,指挥官。
了解更多
DDF3 40 2023 年 1 月 7 日 下午 12:34
C# Heeeelllpp :)
I hate Vstudio :) every thing is so complicated

I made a C# project windows , I am trying to update a label's Text

Here is the code i have on the Form
namespace Meg1 { public partial class MainF : Form { public MainF() { InitializeComponent(); } public void SetLabel1(string s) { label1.Text = s; } } } and on the designer i set the label to be public public System.Windows.Forms.Label label1;

and on the main program.cs i have
namespace Meg1 { internal static class MainP { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainF()); MainF frm = new MainF(); frm.SetLabel1("Hello There"); } }

So it builds ok , and i can run the exe , but the label text doesn't change , so what am i doing wrong ?
< >
正在显示第 1 - 15 条,共 68 条留言
XKorpion 2 2023 年 1 月 7 日 下午 12:53 
LOL how is this related to this Steam "app"? ;) So I think your issue is that you're changing the label in "frm" which is an entirely different object in memory than the mainF object that Application.Run was handed.

when you make the statement:
new foo()
is equivalent to saying in english: "Hey program allocate for me a new object/memory area of type foo"

MainF frm = new MainF(); is an assignment operation.

Try doing this:

//Application.Run(new MainF());
MainF frm = new MainF();
frm.SetLabel("Hello World");
Applicaiton.Run(frm);
DDF3 40 2023 年 1 月 7 日 下午 1:55 
OK this works before the form shows

MainF frm = new MainF();
frm.SetLabel1"Hello World");
Application.Run(frm);

But this one doesn't show . I want to be able to set the label text after the form shows

MainF frm = new MainF();
Application.Run(frm);
frm.SetLabel1("Hello World");

OH and it is related to CNC i was going to attempt to change my Pascal Meg Extractor to C#
Once i get how you do a few things LOL

Ok I have have tried this
Application.Run(frm);
frm.SetLabel1("Hello World");
frm.label1.Text = "Hello There";
frm.label1.Invalidate();
frm.label1.Update();
frm.label1.Visible=false;

and it has no effect on the label at all
最后由 DDF3 编辑于; 2023 年 1 月 7 日 下午 2:39
Nyerguds 8 2023 年 1 月 8 日 上午 6:42 
"Application.Run" does not end until your form is closed. So anything behind that is not executed when you want it. You can easily see this by debugging through the code line by line.

I don't know why you want to change things in your form from the Main() function, but, it just doesn't work that way. Put any initialisation code either in the form's constructor, under the "InitializeComponent()" line, or make a "Load" or "Shown" event, and put it in there.

To make a "Load" event, go to the UI editor and double click the form background and it'll make the listener and the function. For other events, make sure you have the form selected (and not one of the controls), and in the form's properties (if you can't find it, press alt+enter) go to the events tab (with the lightning bolt) and find the right event you want the form to make a function for.

Note, if you make a function to handle an event, and decide not to use it later and delete it, you will need to manually open "MainF.Designer.cs" and also delete the line in there that linked a listener to that function. That file contains all the code generated by the visual editor. This is mainly the variables of the UI controls, and the InitializeComponent() function that applies all their initialisation and positioning.
最后由 Nyerguds 编辑于; 2023 年 1 月 8 日 上午 7:27
DDF3 40 2023 年 1 月 8 日 下午 12:32 
引用自 Nyerguds
"Application.Run" does not end until your form is closed. So anything behind that is not executed when you want it. You can easily see this by debugging through the code line by line.

I don't know why you want to change things in your form from the Main() function, but, it just doesn't work that way. Put any initialisation code either in the form's constructor, under the "InitializeComponent()" line, or make a "Load" or "Shown" event, and put it in there.

To make a "Load" event, go to the UI editor and double click the form background and it'll make the listener and the function. For other events, make sure you have the form selected (and not one of the controls), and in the form's properties (if you can't find it, press alt+enter) go to the events tab (with the lightning bolt) and find the right event you want the form to make a function for.

Note, if you make a function to handle an event, and decide not to use it later and delete it, you will need to manually open "MainF.Designer.cs" and also delete the line in there that linked a listener to that function. That file contains all the code generated by the visual editor. This is mainly the variables of the UI controls, and the InitializeComponent() function that applies all their initialisation and positioning.


OH! now it starts to make sense.. i didn't try the debugger till later and i didn't set a break point there in the Main()

Yeah i gave up on the using Main() to set the labels

I did get the labels to work i added a button
then added this to my Form

private void button1_Click(object sender, EventArgs e)
{
Test ts = new Test();
string name = "";
SetLabel1(ts.Split(out name));
label2.Text = name;
}

then on a new class page

public class Test
{
public void SplitPath(string path, out string dir, out string name)
{
int i = path.Length;
while (i > 0)
{
char ch = path;
if (ch == '\\' || ch == '/' || ch == ':')
{
break;
}
i--;
}
dir = path.Substring(0, i);
name = path.Substring(i);
}

public string Split(out string named)
{
string dir, name;
SplitPath(@"c:\Windows\System\hello.txt", out dir, out name);
named = name;
return dir;

// Console.WriteLine(dir);
// Console.WriteLine(name);
}
}
}
Nyerguds 8 2023 年 1 月 8 日 下午 2:36 
Put your code in a "code" tag here, so surrounding "i" with [ ] doesn't make everything italic :p

By the way, "String" class has a perfectly usable Split() function already. You can even give it multiple characters to split by, and tell it whether or not to keep empty values in the resulting array.

And the static "Path" tool-class already has a bunch of toolsets to split filenames, folder names and extensions. It's one of the things I really like about the .net framework, in fact; it has an enormous amount of standard tools already built in.
最后由 Nyerguds 编辑于; 2023 年 1 月 9 日 上午 2:37
DDF3 40 2023 年 1 月 9 日 上午 9:28 
Ha i never even noticed the italics

well i have managed to get the steam path to cncremastered\data\ from the registry, i put this in Main()

// open SKey = @"SOFTWARE\Valve\Steam" RegistryKey regKey = Registry.CurrentUser.OpenSubKey(Globals.SKey); // open SPath =@"SteamPath"; Globals.STPath = regKey.GetValue(Globals.SPath).ToString(); // just messing around here int x = Globals.STPath.Length; int i = 0; string s = ""; while (i < x) { char ch = Globals.STPath;
if (ch == '/')
{
ch = (char)92;
}
s = s + ch;
i++;
}
// add the rest of the path
Globals.STPath = s + @"/steamApps/common/CnCRemastered/Data/";
// replace all of the / with \
Globals.STPath=Globals.STPath.Replace('/','\\');[/code]

Humm its adding my code end block to the end of my code, well two code end blocks didn't solve it.

and i put this in globals

private static string _stpath; public static string STPath { get { return _stpath; } set { _stpath = value; } }

as well i changed the splitpath function to use split()

public void SplitPath(string path, out string dir, out string name) { string[] str = path.Split('\\'); int count = str.GetLength(0); string s = ""; for (int i = 0;i <= count-2;i++) { if (i < count-2 ) s = s + str +'\\';
if (i == count-2) s = s + str;
}
dir = s;
name = str[count-1];
}[/code]

Ok im going to try to get a file list of whats in the data directory next and display it in a listbox
最后由 DDF3 编辑于; 2023 年 1 月 9 日 下午 2:34
DDF3 40 2023 年 1 月 9 日 下午 2:29 
How do you access a class that has already been created

eg : Foos foo = new Foos();


but some other place i need access to the class Foos again , but don't want to create a new copy of it

I got the file names into a list box no problem , now i'm trying to decide how i want to access the meg file
最后由 DDF3 编辑于; 2023 年 1 月 9 日 下午 2:36
Nyerguds 8 2023 年 1 月 10 日 上午 6:07 
引用自 DDF3
Ha i never even noticed the italics

well i have managed to get the steam path to cncremastered\data\ from the registry, i put this in Main()
Note that RegistryKey is an IDisposable object. Such objects should always be cleaned up after use, since they use resources outside the automatic garbage collection scope of the .Net framework. Manually, this is done by calling "regKey.Dispose()" (in fact, having a "Dispose()" function is a good indicator of whether something is IDisposable), but to automate this, c# has the concept of a "using (SomeClass obj = new SomeClass()) { ... }" block; this automatically takes care of the cleanup, and since it uses a section in brackets, the object only exists inside that block, meaning it also makes sure that you can't try to use the object after it is already disposed.

This stuff is vitally important when it comes to stuff like closing file streams after reading data from them, since opening a stream tends to lock the file for other applications.

This is from the code I use to find the Steam game library containing the game:
object path; // First try 64-bit registry... try { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Valve\Steam")) { if (key != null && (path = key.GetValue("InstallPath")) != null) { return path.ToString(); } } } catch { // Ignore and continue. } // Then try 32-bit registry...
"using" blocks also have the advantage that they will always ensure that the object is disposed, even if an exception occurs inside the block.

You can copy that whole class from my project if you want; it's open source for a reason.

https://github.com/Nyerguds/CnCTDRAMapEditor/blob/master/CnCTDRAMapEditor/Utility/SteamAssist.cs

Called here:

https://github.com/Nyerguds/CnCTDRAMapEditor/blob/master/CnCTDRAMapEditor/Program.cs#L75

引用自 DDF3
How do you access a class that has already been created

eg : Foos foo = new Foos();

but some other place i need access to the class Foos again , but don't want to create a new copy of it
Copy? If the class is either inside your project, or accessible from the project references, but it is not in the same namespace as the current class, you have to specifically tell the current class that it should reference it. This is done by adding a "using" statement for it at the top of the file. This is not necessary for classes in the same namespace. (Note, don't confuse this with the "using" blocks I mentioned before; that's a completely different thing.)

On most new classes you make, you'll at least see something like:
using System; using System.Collections.Generic; using System.Linq; using System.Text;
Normally when you type a class name that is accessible like that, but does not have a "using" statement in the current class yet, you can hover over it and get an "error" icon. Click the icon and it'll give the option to add the missing "using" statement:

https://i.imgur.com/EoWacxg.png
(this is the flood fill code from the map editor :steamhappy:)

You can also reference it by full namespace name (the third option in the list there; to change the current text to "Utility.BlobDetection"), but that's generally more tedious than a global import with a "using" statement that works for the whole file.
最后由 Nyerguds 编辑于; 2023 年 1 月 10 日 上午 10:59
DDF3 40 2023 年 1 月 10 日 上午 11:04 
I will stick with what i have written for now , its the only way i learn :)

I see on Megafile.cs they have "using " but i cant figure out what class they are referring to.
EG: using (var magicNumberReader = new BinaryReader(megafileMap.CreateViewStream(readOffset, 4, MemoryMappedFileAccess.Read)))

Ok i have on my form a listbox with all of the Meg files (LBFiles)
when i click on one of the Items it Loads up the Meg file ( i just used MegaFile.cs and changed the stringtable to public) and that fills in the LBItems (listbox for the items in the stringtable of the Meg file )

Now when i do this Megafile Mega = new Megafile(MegPath); I assume it creates a totally new Class Instance right ?

So it brings me to the question of how do i get rid of the previous instance ? Or does it dispose of its self .

So i tried it this way , but the commented out section gave me errors ,the idea was if there is an existing class then i dispose of that and create a new one
private string SelItem = " "; private string MegPath = " "; private void LBFiles_MouseDown(object sender, MouseEventArgs e) { int x = LBFiles.SelectedIndex; SelItem = LBFiles.Items[x].ToString(); MegPath = Path.Combine(@Globals.STPath,SelItem); SetLabel1(MegPath); // if (Megafile != null) // { // Megafile.Dispose(); // } // else // { Megafile Mega = new Megafile(MegPath); LbItems.Items.Clear(); foreach (string item in Mega.stringTable ) { LbItems.Items.Add(item); } // } }


OH i kinda see now so i should be saying something like using(Megafile Mega = new Megafile(MegPath)) because the MegaFile is IDisposable
最后由 DDF3 编辑于; 2023 年 1 月 10 日 上午 11:12
Nyerguds 8 2023 年 1 月 10 日 下午 2:16 
"var" is a shortcut that automatically adapts to the type being put into it. So in that first case, it's just the BinaryReader mentioned just behind it. Hover over the variable and it should tell you what type it is. I prefer not using "var", since it just makes things confusing in my opinion.

Your code there fails because you're comparing a class type (MegaFile) with null. A type can't be compared with null; it's not a real object. It's just the "template" which the real objects are created from.

If you define a new meg file with the code "Megafile Mega = new Megafile(MegPath);" then your object variable is "Mega", so if you want to dispose the object, you need to call Dispose() on that "Mega" variable. The class itself will not contain that; any function that can be called on the bare class name is a static function that acts independently from any objects.

Note, c# naming convention is normally to give class names and function names CamelCase, and variables lowerCamelCase. So a variable like your Megafile object there would normally be called "mega", not "Mega". This convention also makes it easier to distinguish variables from class names.

引用自 DDF3
OH i kinda see now so i should be saying something like using(Megafile Mega = new Megafile(MegPath)) because the MegaFile is IDisposable
Yep! With the brackets block behind it, otherwise it's only valid for a single line of code. And it means you don't have to worry about closing any file streams it has open internally; "Dispose()" (or "using") is a promise to the user that all such stuff will be cleaned up afterwards.
最后由 Nyerguds 编辑于; 2023 年 1 月 10 日 下午 2:44
DDF3 40 2023 年 1 月 11 日 上午 10:39 
I understand the var part now

Ha naming convention I'm used to Pascal where the case doesn't matter . I am trying now though with the names .

Though i do like pascals use of classes a lot more .
EG : var Mc : MyClass; , Mc := MyClass.Create; Then i can use Mc all over my application until i need to dispose of it then it is as simple as Mc.Free;

Unlike in C# where it seems like i have to keep creating new copies of the class like
using (Megafile mega = new Megafile(MegPath))
{
}


I am making progress, It now fills in the Meg file listbox when the form shows.
I added an Extract One , and ExtractAll buttons , and they even work :)
I added a progress bar to the Extract All function and update a label with the file it saved , In the proper directories even.

It also will display the XML files .

But i ran into a snag when i tried to put a Tga image into a picture box seems like it does not like that lol. So now i guess ill have to use the TGASharp Library.
Nyerguds 8 2023 年 1 月 11 日 下午 4:41 
引用自 DDF3
Unlike in C# where it seems like i have to keep creating new copies of the class like
using (Megafile mega = new Megafile(MegPath))
{
}
You don't have to; if you make sure to keep track of things and dispose it eventually, then you can obviously just make it a private class variable and keep it alive during the whole thing.

Though in that case, in general, the class itself should inherit IDisposable and you should make sure that its own Dispose function handles the cleanup when the object is disposed.

For forms, this already exists; the Dispose function is in the .designer.cs file.

On a related note, many people seem to ignore it, but the fact forms are IDisposable also means that any sub-dialogs shown for opening stuff like a little settings window should generally also be done with a "using" block.

引用自 DDF3
But i ran into a snag when i tried to put a Tga image into a picture box seems like it does not like that lol. So now i guess ill have to use the TGASharp Library.
Yea, that's what the editor does, too.
最后由 Nyerguds 编辑于; 2023 年 1 月 11 日 下午 10:05
DDF3 40 2023 年 1 月 12 日 下午 8:49 
Well i got the TGA and DDS displayed with no problem , and now i am working on the Zip. i have the contents of the zip so far , just need to redo a few things before i can display them.

Thanks for the info so far .
Nyerguds 8 2023 年 1 月 13 日 上午 6:56 
For some strange reason, while debugging on my Win11 machine, the zip stuff keeps showing endless "'System.ArgumentOutOfRangeException' in mscorlib.dll" lines in the Output window. It doesn't actually break anything, but it slows down everything to a crawl while it's loading the graphics.

Bizarrely, running normally without debugging doesn't have the issue. I also don't have the problem on my old Win7 PC.
DDF3 40 2023 年 1 月 13 日 下午 12:00 
Maybe something is set differently in the debuggers .. Just a guess lol

Well i now have the zips displaying the Tga's and i can play the Wav files, plus that it even saves the forms size in the app.config and sets that to be its starting size
< >
正在显示第 1 - 15 条,共 68 条留言
每页显示数: 1530 50