Diskuze: Okna jsou bez ovládacích prvků a negungují
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
Zobrazeno 48 zpráv z 48.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Co to je za okna? Klasický MessageBox (tvarem to tak vypadá), nebo sis
tvořil něco vlastního?
Mimochodem, používáš nějaký verzovací systém?
Tak začni znova po malých úpravách - nejhorší co můžeš udělat je přepsat půl programu naslepo -zvlášť když děláš něco nového, co nemáš ověřené.
Má to vyskakovat a přepisovat určitý okna ve windowsu, respektive v jednom software Tohle je jen test takže jsem to dal vyskakovat na základě logu, bez ohledu na to jaký okna jsou otevřený, ale když ten software otevřu (ten třetí strany), tak se nezobrazují na oknech toho softu, prostě to vůbec nefunguje i když konstruktory přebírají parametry v pořádku, pokud jsem něco nepřehlédl
Tak se vrať k původní verzi, která ještě fungovala,a postupně začni provádět úpravy na aktuální verzi, ale pouštěj to s každou úpravou. V jednu chvíli to přestane fungovat a máš zdroj problému.
Tak já to nyní volám z eventu (to vyskakování těch oken), a z něj se nezobrazí vůbec žádný okno správně, ani bezparametrickej konstruktor jako...
Settings pc = new Settings();
pc.Show();
To zobrazí stejně špatně jako ty okna v tom obrázku... Takže to není parametrama v kódu, ty to předává správně problém je někde jinde. Hlava mi to nebere...
Tak to si vyresil ne? Je to celé STA, pravděpodobně ti to nebude fungovat, pokud to budeš otevírat z jiného vlákna.. Ten kdo ten objekt totiž vytvořil (to vlákno), tak to je jeho vlastníkem a jen to do něj může zapisovat (kreslit) atd. Otevírání toho okna marshalluj do hlavního vlákna.
Snažil jsem se na to přijit, ale nepřisel jsem na to
Pořád se to snaží dostat do jiného vlákna, zatímco ta původní verze jede a okna se otviraji stále na hlavním vlákně, tak ty popup okna u nové verze se otevírají na novém vlákně a tam to dělá to co to dělá.
Kdyz si uz myslim, ze jsem dostal vsechno do hlavniho vlakna, tak to stopnu na initializecomponent popupu a zase to jede na jinym
Pořád se to snaží dostat do jiného vlákna...
samo se to do jiného vlákna cpát nebude, někde jsi to musel napsat, aby se to otevíralo v novém vláknu. Bez tvého zásahu by všechno běželo jen v hlavním vlákně...
A co kdyby ses už teda pochlubil nějakým kódem - třeba původní funkční vs nový nefunkční ?
Tak ten úsek kódu co otvírá ty okna zas tak dlouhý snad nebude ne ?
co je zajimavý je tohle:
//Event na _fileSystemWatcher.Changed += WatcherChangedEvent;
private void WatcherChangedEvent(object sender, EventArgs e)
{
Settings set = new Settings();
set.Show(); //tohle to zobrazi stejne spatne jako v tom obrazku
this.Invoke(new Action(() => {
Settings seet = new Settings();
seet.Show(); //tohle to zobrazi jak ma
//tady jsou dalsi metody ... samozrejme tam nezobrazuju setting,
// ale jen takova ukazka, okna se zobrazuji z dalsi tridy kterou volam
// tady, a bezi to vsechno pod main threadem
}));
}
Tak v první řadě bys neměl používat "klíčové slovo" set - to je vyhrazeno pro setter property
asi mám teda halucinace, ale já vidím
Settings set = new Settings();
set.Show();
A co je to vůbec za třídu ta Settings - nějaká tvoje, nebo internal sealed partial class Settings z Properties ?
Podle toho jak ji používá tak by si tipnul že je to form.
to jsem dal jen jako ukázku toho jak to funguje v eventu watcheru mimo
invoke a s invoke...
Vůbec jsem to nespouštěl, protože je to mimo. Jinak to vůbec takto
nepoužívám, ano je to klasickej form s nastavenim softu...
Teďka musím vytáhnout to nejdůležitější z toho softu, aby mi nekdo poradil, protože jsem už zoufalej z toho...
Takové nekonkrétní narychlo slátané ukázky typu "je to nějak podobně jako tohle" jsou k ničemu
schválně jsem si to zkusil a ono to chodí jak má - proč by taky nemělo - dal jsem to teda na buttonClick
private void button1_Click(object sender, EventArgs e)
{
Form2 newForm = new Form2();
newForm.Show();
this.Invoke(new Action(() => {
Form2 newForm2 = new Form2();
newForm2.Show();
}));
}
a otevřou se dva nové formy
VSE VELMI ZJEDNODUSENE, abych priblizil problem
public partial class MainWindow : Form
{
readonly FileSystemWatcher _fileSystemWatcher = new FileSystemWatcher
{
Path = Path.GetDirectoryName(Properties.Settings.Default.PokerStarsPath),
Filter = "xxx.log.txt",
EnableRaisingEvents = false,
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.Size
};
public MainWindow()
{
InitializeComponent();
//Udalosti na changed
_fileSystemWatcher.Changed += WatcherChangedEvent;
}
private void WatcherChangedEvent(object sender, EventArgs e)
{
//aby bezelo pod main thradem, tim ten problem zpusobeny neni
// ale pro zjednoduseni
this.Invoke(new Action(() => {
AnalyzeLogs analyzelogs = new AnalyzeLogs(_psRun, _ftpRun, _wpnRun);
analyzelogs.LogAnalyzeAndSendData();
}));
}
}
Z eventu to jde sem ->
class AnalyzeLogs
{
public delegate void MsgHandler();
public event MsgHandler MsgFound;
public AnalyzeIt analyzeit { get; set; }
static List<string> _sendedData = new List<string>();
public AnalyzeLogs(bool psRun, bool ftpRun, bool wpnRun)
{
MsgFound += FoundEvent;
}
public void LogAnalyzeAndSendData()
{
try
{
using (
FileStream fsreader =
new FileStream(
Properties.Settings.Default.PokerStarsPath,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite))
{
using (StreamReader reader = new StreamReader(fsreader))
{
{
//radkovac
for (int radek = 0; radek <= _logPos; radek++)
reader.ReadLine();
//prvni cyklus; cte radky z pokerstars.log.0, ktere se maji
// vytahnout do log.txt
string text;
while ((text = reader.ReadLine()) != null)
{
if (text.Contains("MSG_X"))
{
//prida data do _sendedData
}
if (text.Contains("MSG_Z"))
}
//prida data do _sendedData a vypali event
MsgFound();
}
}
}
}
}
}
private void FoundEvent()
{
//tady to utridi a posle data do ->
analyzeit = new AnalyzeIt("Y", Kar1, Kar2, BB,
Sta, ToCl, S, Id, Pozice);
//posila vysledky z analyzeit do analyzelight, protoze
// analyzeit by zabirala strasne moc prostoru,
// vzhledem k x tisic radkum porovnavaich dat
// zhruba 1GB RAM na 100 odeslani
//KONSTRUKTOR... Data nejsou podstatna
AnalyzeLight light =
new AnalyzeLight(analyzeit.ShowPicture1(),
analyzeit.ShowPicture2(),
analyzeit.ShowPictureS(),
analyzeit.ShowPictureSLow(),
analyzeit.ShowPictureVsR(),
analyzeit.ShowPictureVsL(),
analyzeit.ShowPictureVsO(),
analyzeit.Efective.ToString(),
analyzeit.Bb.ToString(),
analyzeit.Sta.ToString(), analyzeit.ToC,
analyzeit.Kar1, analyzeit.Kar2,
analyzeit.St, analyzeit.ID,
analyzeit.RN,
analyzeit.Gr, analyzeit.Na,
analyzeit.Po, analyzeit.NCo,
analyzeit.IsG, analyzeit.Sit);
//tady se vytvori nove okno
new ShowIt(light);
}
}
//ZOBRAZOVAC a vyskakovac oken :)
// DATA SEDI, I V TOM POPUPOVEM OKNE
// ALE ZOBRAZUJE TO TAK JAKO V PRVNIM OBRAZKU
// KDYZ TADY DAM SHOWDIALOG() MISTO SHOW(), TAK SE ZOBRAZI
// I DO KONZOLE VYPISE JEN PRVNI UDAJ (PRO PRVNI OKNO) A
// POTOM SE TO ZASTAVI, PRITOM TO MA NACIST DALSICH 200 UDAJU
// S SHOW(), SE TO SICE V KONZOLI ZOBRAZI, I ZACNOU VYSKAKOVAT OKNA,
// ALE VYSKAKUJI TAK JAK V TOM PRVNIM OBRAZKU, BEZ CEHOKOLI :)
class ShowIt
{
static PopupWindow[] cardspopup = new PopupWindow[1000];
static List<long> IDs = new List<long>();
long _idT;
static int _cSt = 0;
public ShowIt(AnalyzeLight light)
{
if (light != null)
{
_idT = light.ToID;
if (IDs.Contains(light.ToID))
{
int x = 0;
foreach (long i in IDs)
{
if (light.ToID == i)
{
cardspopup[x].Actualize(light);
break;
}
x++;
}
}
else
{
IDs.Add(light.ToID);
//TADY SAMOZREJME MAM InitializeComponent();
cardspopup[_cSt] = new PopupWindow(light, _idT, _cSt);
cardspopup[_cSt].Show();
_cSt++;
}
}
}
}
No to ti povím teda - to je na můj vkus pěkná divočina otvírat okno v
konstruktoru třídy - tam bych hledal problém - konstruktorem bys měl
předávat třídě parametry ale rozhodně ne provádět nějaké akce - takže
všechno z konstruktoru hoď do metody a teprv jejím voláním okno
otvírej.
Jiného nic mně nenapadá
Me tam tedy desi kazda druha radka :-/ Mozna nejvice řádka:
new ShowIt(light);
Vůbec bych se nedivil, kdyby to bylo tímdle a garbage collectingem
Uplne vidim, jak mu runtime smazne pulku toho "formuláře" ještě než ho zobrazí Nerad bych tu ale zabředával do GC a refcountingu Už když vidím nelockovaný static a doufání v to, že mě bude někdo marshallovat do STA, aby nedošlo k race condition ve mně Invoke()uje myšlenku, že to možná někdy zobrazí okno, jindy uvaří kafe a možná občas odstartuje nukleární válku.
@Dog první co udělej je, že zkusíš instance někam přiřadit do proměnné, když už tedy máš side efekty v constructoru..
Takže GC může smazat z haldy třídu, i když právě probíhá její konstruktor? (pokud na ni neukazují reference, jak říkáš, new ShowIt() )
statické pole tisíce oken je taky docela bomba - celé to vypadá na hodně špatný návrh aplikace
EE to nemůže. Ale jsme v single-thread frameworku, ten volá mj. nějaký Repaint a potřebuje k tomu data. Dog má v kódu:
//TADY SAMOZREJME MAM InitializeComponent();
Tento komentář, takže hádám, že ShowIt bude asi i nějaká komponenta.. Těžko říct co tam má. Z toho co mu to vykresluje si osobně myslím, že tam má buďto časově závislou chybu, nebo tam zabije hlavní vlákno. pořád si myslím, že nám důležité informace zůstávají skryty
Já bych se na to klidně kouknul podrobněji, ale jen pokud by dal k dispozici fakt minimalni repro solution, takhle stejně to nejdůležitější určitě nedal..
Dal jsem to mimo konstruktor, v konstruktoru jsem nechal jen inicializaci
tridy AnalyzeLight
Ted to volam takhle, ale nic se nezměnilo:
ShowIt showit = new ShowIt(light);
showit.GetWindow();
To co nechapu je, ze ve tride ShowIt, kdyz dam misto:
cardspopup[_cSt].Show(); ... tohle cardspopup[_cSt].ShowDialog();
Tak to to popupové okno normálně zobrazi, ale vlakno se ukonci hned po
prvním cardspopup[_cSt].ShowDialog(); ... Jako by nevědělo, že má
pokračovat v cyklu while
while ((text = reader.ReadLine()) != null)
{
// tady ma pokracovat, show() tady sice pokracuje, ale nezobrazuje okna :(
...
}
*** V každém případě díky moc za cenné rady, např. že v konstruktoru se nic nezobrazuje, jen inicialzuje apod...
Když otevřeš dialogové okno (ShowDialog), tak program čeká, než ho zavřeš, pak teprve pokračuje dál.
Ten while cyklus. Jak trvá dlouho? Jsi si jistý na 100% ze dojede a ze dojede v rozumné době?
No trvá 40 sekund, když to načtu naráz, procita 50 tisic radku ale až to bude real time tak to bude skákat maximálně po 100 řádcích za změnu, no s tím showdialog() se to zobrazí a zobrazuje to okno, musím to sice vždycky zavřít, ale zobrazuje se to, každý okno má svůj konstruktor...
cardspopup[_cSt] = new PopupWindow(light, _idT, _cSt);
a několikrát se zavolá actualizer toho okna...
cardspopup[x].Actualize(light);
Kterej se po tom zobrazení showdialogem už samozřejmě neatualizuje protože okno se musí zavřít aby to mohlo pokračovat a už neexistuje... Ale zobrazí se ty okna volané pomocí konstruktoru, což mi hlava nebere.
Tak netuším čím to může být, snad tím, že když se to automaticky nezastaví po zobrazení okna tak se to začne nějákým způsobem přepisovat něco někde, nebo že to okamžutě po zobrazení okna shráhně garbage... Nevim
A co jste mysleli tím nezabezpečený staticem? měl bych to mít locklý, nebo nejákej semaphore? Neznám právě taková ty nepsaná pravidla programování Nevíte kde bych se o tom mohl něco dočíst?
Dále, když v tom eventu nahradím
ShowIt showit = new ShowIt(light);
showit.GetWindow();
tímto
//Což není žádná komponenta mého softu, prostě form
Form form = new Form();
form.Show();
Tak to začne pálit jeden form za druhým, správně zobrazených, ale když dám zobrazit nějákej form v mém řešení, tak to začne zobrazovat zase jako v tom prvním obrázku např.
Settings form = new Settings();
form.Show();
//nicméně když tam dám ShowDialog(); tak se to zobrazí normálně,
// ale vzhledem k tomu,, že to musím zavírat tak je to nepoužitelné,
// ale přijde mi to paradoxní celý
Ten while co trva 40sec běží v hlavním vlakne? Tak to může být dost pravděpodobně pricina. Pokud totiž delší dobu takto zabijes hlavní vlákno svojipraci, tak nemůže obsluhovat události pro COM objekty. Kdyby to bylo wpf, vyhodí ti exception, že se zahltila event queue a crashne ti, winforns se chová jsem podivne.
Píšeš, že projíždíš 50 000 řádků a máš tam nějaké pole o
velikosti 1000 - nemůže se ti stát, že se ti index (to x) dostane přes ten
1000?
Nebyl by místo toho pole lepší List?
To by mu to za běžných okolností vyhodilo OutOfBoundException, pokud je to v nějakém threadu, co si vytvořil sám růčo, tak mu ten thread tiše spadne. Pořád ale si nejsem jistý, jestli se mu tam pouští více threadu nebo ne.. a pokud mu tam něco thready pouští (nějaký ten Watcher), tak to tam může tiše polykat.
Takhle dlouhé záležitosti by se měly zpracovat asynchronně - buď
BackgroundWorker, nebo Async /Await - každé pracuje jinak, těžko říct, co
je pro tvůj případ lepší.
Taky když jsem si kdysi zkoušel jak chodí FileSystemWatcher, tak jsem měl
myslím problém s tím, že když otevřeš soubor, který vyvolal event, tak
si vlastně vyvoláš opětovně eventhandler a pokud to nemáš dobře
ošetřené, tak tak se můžeš pěkně zacyklit
Takže to všechno ukazuje na to, že chyba je v tom PopUpWindow - můžeš sem dát kód?
Tohle byla poslední funkční verze... Ve které se vsechno zobrazovalo, jak mělo... je to teda ještě mnohem ale mnohem horší kód než to, co jste viděli
měl jsem to na timeru, takže když byl log dlouhej, třeba 500k řádků tak se muselo načítat pořád všechno dokola načítat třeba 10x za vteřinu a ta struktura v analyzelogs.LogAnalyzeAndSendData(); byla jiná že to třeba něco nenačetlo apod... nová verze načítá 100% dat, který chci načíst, ale problém je s tim zobrazovanim.
private async void TimerTickEvent(object sender, EventArgs e)
{
AnalyzeLogs analyzelogs = new AnalyzeLogs(psRun, ftpRun, wpnRun);
await Task.Run(() =>
{
analyzelogs.LogAnalyzeAndSendData();
});
//GTOSolution
AnalyzeIt analyzeit = analyzelogs.analyzeit;
if (analyzeit != null)
{
try
{
AnalyzeLight analyzelight = new AnalyzeLight(
analyzeit.ShowPicture(),
//dalsi parametry
);
ShowIt table = new ShowIt(analyzelight);
File.WriteAllLines(@"log.txt", pslog);
}
catch { }
}
}
Já jsem do té třídy s PopUpWindow vůbec nerýpal, a proč by to nezobrazovalo ve FoundEventu teda i tak primitivní věc, jako:
Settings settings = new Settings(); //settings je trida : form v mym projektu
settings.show();
Data to tam posila spravne, ale...
//V KAZDEM PRIPADE DEKUJI ZA VASI TRPELIVOST
A tim eventem to to taky nebude, protoze i kdyz dam do konstruktru mainformu na konec :
AnalyzeLogs analyzelogs = new AnalyzeLogs(psRun, ftpRun, wpnRun);
analyzelogs.LogAnalyzeAndSendData();
Tak problem stale pretrvava... Uz vazne nevim... A to PopUpWindow jsem neupravoval a nic jsem s nim nedelal, tak si nemyslim, ze to tim bude, ale klidne ho sem dam...
Předpokládám, že nemusím v zobrazovacím okně vytvářet novou instanci AnalyzeLight:
public CardsPopup(AnalyzeLight analyzelight, long id_turnaje, int c_stolu)
{
InitializeComponent();
A stačí to inicializovat přes parametr... Jsou to ta data, která se mají
zobrazit, jako texty, obrazky apod...
Resp. nemusím:
this.analyzelight = analyzelight
a potom ty prvky aktualizovat pres this.analyzelight
nic jinýho mě nenapadá...
//Tahle inicializace fsw nezobrazovala ve svem eventu show() vůbec od ničeho správně
// tak jsem tam dal místo ní, klasickou pomoci sady nástrojů a docílil jsem alespoň
// zobrazení formuláře z mého řešení v eventu
//ŠPATNĚ
readonly FileSystemWatcher _fileSystemWatcher = new FileSystemWatcher
{
Path = Path.GetDirectoryName(Properties.Settings.Default.PokerStarsPath),
Filter = "xxx.log.txt",
EnableRaisingEvents = false,
NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.Size
};
public MainWindow()
{
InitializeComponent();
//Udalosti na changed
_fileSystemWatcher.Changed += WatcherChangedEvent;
}
//ŠPATNĚ
Když dám za volání eventu MsgFound(); v LogAnalyzeAndSendData() break, tak zobrazuje okna i aktualizuje s show(), což je pokrok, ale samozřejmě že musím pořád měnit logfile, abych dosáhl neustálého volání eventu WatcherChangedEvent... Což takhle určitě nejde, ale pokrok...
Zobrazeno 48 zpráv z 48.