Diskuze: WinRT - asynchroní metoda a zamrzání UI
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Tvůrce

Zobrazeno 28 zpráv z 28.
//= 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.
Dokázal by někdo poradit ?
Tyto nové metody neznám, ale určitě je v WPFku něco jako ve WinForms Beckground worker, nebo snad ne?
Teď koukám, že ho tam můžeš normálně použít, pokud chceš dělat jednu úlohu na pozadí, tak se s nějkými asynchronními metodami vůbec nezatěžuj, existují wrappery, co tě od toho odstíní.
To je ten problém. UI prostě zamrzne. A aplikaci potom neuznají. Nevím, v téhle metodě je někde chybě.
Nyní jsem našel zpsůbo jak jednodušše načíst pixely -> byte array.
S tvorbou async metod přes await jsem neměl nikdy problém. V pohodě jsem měl metodu která generovala prvočísla do vysoké hodnoty, přes await a UI nezamrzlo.
Ještě se ozvu jak jsem to vyřešil, nyní už možná mám řešení.
Problém bude v té cizí knihovně.
Vítej ve světě windows 8. Možná by to šlo a lidi z microsoftu
používají (a na konferencích učí) Async a Await. Asi to nedělají ze
srandy králikům.
Posílám update kód. Opavdu už nevím co a jak . Pro update UI se musí využít
Dispatcher. Je divné jedno - když ho nevolám a neupdatuju UI! UI zamrzne.
Když ho Updatuju UI nezamrzá.
Metodu, která generuje volám takto
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
manager.GenerateAsciiHtml(bmp, pixels);
});
Metoda která generuje. GetPixel už je moje metoda.
public void GenerateAsciiHtml(BitmapImage bmp, byte[] pixels)
{
ascii = new StringBuilder();
ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));
for (int h = 0; h < bmp.PixelHeight - Size; h += Size)
{
for (int w = 0; w < bmp.PixelWidth - Size; w += Size)
{
Color color = bmp.GetPixel(pixels, w, h);
ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
color.R,color.G,color.B, getAsciiChar(color.A)));
}
ascii.Append("<br>");
}
ascii.Append("</body>");
}
Metoda naschvál nic nevrací. V tomto případě UI nemrzne. Teď ovšem potřebuju jedno. Buď metoda nastaví text pro výpis přímo v sobě nebo vrátí string. Nastíním durhou situaci. Volání metody změním na
string text = "";
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
text = manager.GenerateAsciiHtml(bmp, pixels);
});
do stringu text se přiřadí vrácený vygenerovaný HTML. Ovšem potřebuju udělat jedno. Binduju properties z manageru, tedy ze stejné třídy která generuje a má položku HTML. Jakimle se pokusím text přiřadit do HTML, UI zamrzne.
Dispatcher má v sobě metodu AsAsync() a ta má v sobě ContinueWith(), což by se mělo zavolat až po dokončení.
Mám v tom huláš a už nevím co a jak. Když udělám async i metodu ne generování dostávám error o tom že zasahuju do jiného vlákna.
Prosím nějaká rada, prostě kudy co a jak ? Děkuji moc !
Ano to jsem zkoušel ale tohle mi prostě nefunguje. Zkoušel jsem i generovat číslo, vypočítavat z nich násobky + odmocniny a UI nezamrzlo. Asi je problém že mám tu metodu na generování a zároveň properties pro UI v jedné třídě.
http://vimeo.com/57608362 Zde podle nich i něco zkouším.
Už fakt nevím jak .
KDyž načítám soubor, napíšu await a vše funguje. Ale tohle mi nestačí, nevím jak to funguje přesně pod pokličkou :/
to si nemyslim, ze to je tou jednou tridou. A funguje to kdyz pocitas ty cisla a pak neco vratis?
Ano, počítám a vracím double. Schvále jsem měl i tu samotnou metodu async a každé nově vypočtené jsem připsal do souboru opět přes await (jinak to nejde). Vše fungovalo, UI nezamrzlo
Asi už musím vypadat jako totální blbec. ale já opravdu už nevím jak
Už jsem ve stavu kdy bych to
nejradši všechno vyhodil oknem
.
Shrnu co tedy potřebuju a co mám.
Třída DataManager: Drží v sobě data pro Binding, je to čistě Model. Dříve jsem tam měl i metodu pro vygenerování HTML ASCII z obrázku. Přesunul jsem ji.
Třída PhotoAsciiWorker: Obsahuje metodu pro vygenerování HTML ASCII.
Ze třídy MainPage.xaml.cs -> třída která má přístup k View, zavolám metodu GenerateAScii z PhotoASciiWorker. Metoda by měla být asynchronně. Tedy aby UI nezamrzlo a napsalo třeba Working...
Co a jak nastavit ?
Do teď mi vždy stačilo označit metodu async a zavolat ji přes Await. Napíšu "možný" způsob zpracování
textBlock.Text = "Generating...Please wait";
Task<string> task = worker.GenerateAscii(.....) ;
string result = await task;
textBlock.Text = result;
// ---> UI zamrzne
// nebo
string reesult = await worker.GenerateAscii(...)
// UI zamrzne
Už fakt nevím co dělat
Nechceš se na to vykašlat a použít nové vlákno?
A jak ? S vlákny moc
kamarád nejsem. Tohle je navíc nové vlákno, je to akorát nový způsob http://msdn.microsoft.com/…h191443.aspx#… . Chápu jak to
funguje ale nechápu proč to nefunguje v tomhle případě. Přitom když si
udělám metodu která generuje náodná čísl,a násobí a dělá odmocninu +
zapisuje furt do txt, UI nezamrzne
Tak nyní zkouším už všechno možný. Nevím, prostě nevím. Zde třída PhotoAsciiWorker. Schválně jsem dal nastavení hodnot pro výpočet do jiné metody.
class PhotoAsciiWorker
{
byte[] pixels;
BitmapImage bmp;
int size;
public void SetValues(BitmapImage bmp, byte[] pixels, int size)
{
this.pixels = pixels;
this.bmp = bmp;
this.size = size;
}
public string GenerateAsciiHtml()
{
StringBuilder ascii = new StringBuilder();
ascii = new StringBuilder();
ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));
for (int h = 0; h < bmp.PixelHeight - size; h += size)
{
for (int w = 0; w < bmp.PixelWidth - size; w += size)
{
Color color = bmp.GetPixel(pixels, w, h);
ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
color.R, color.G, color.B, getAsciiChar(color.A)));
}
ascii.Append("<br>");
}
ascii.Append("</body>");
return ascii.ToString();
}
Zde volání metody
manager.HTML = "Working...";
worker.SetValues(bmp, pixels, manager.Size);
Task<string> task = Task.Run(new Func<string>(worker.GenerateAsciiHtml));
string result = await task;
manager.HTML = result;
Dostunu tento error:
The application called an interface that was marshalled for a different thread.
A nemělo by být GenerateAsciiHtml async?
Nn, zde ukázka testovacího progámku.
Task<double> task = Task.Run(new Func<double>(Calculate));
double result = await task;
txResult.Text = result.ToString();
public double Calculate()
{
double r = 0;
for (int i = 0; i < 10000 * 500 *200; i++)
{
r += Math.Sqrt(i);
double bl = r * r * r * - Math.Pow(i,2) + Math.Sqrt(r);
}
return r;
}
Vše funguje. UI nezamrzne
Tak tak udělej i ty pixely, pokud funguje o, tak musi i pixely.
To je to, nefunguje a já už absolutně nemám tušení proš nebo jak mám prostrčit skrz
Func i parametry metody které potřebuje ?
Už toho mám akorát dost. Misaz mi poslal video kde ukázali jak dělat složité operace v jiném Threadu než je Thread UI -> UI nezamrzne. Kód může vypadat takto.
private async void btnAsync_Click(object sender, RoutedEventArgs e)
{
// vytvoří nové vlákno, čeká na jeho dokončení. "Vyskočím" z //metody pryč. UI je aktivní dál
long vysledek = await Task.Run<long>(() => Calculate(1000000000000));
/// dokončilo se vlákno, pokračuju dál
this.txResult.Text = vysledek.ToString();
}
public long Calculate(long n)
{
long r = 0;
for (long i = 0; i < n; i++)
r += i;
return r;
}
Vše funguje jak má. Počítač počítá jak divý ale UI nezamrzlo. Nyní můj výpočet.
bmp = BitmapaNačtená ze souboru. Pixels = byte[] pixelů, size -> poměr pixel / char
manager.HTML = "Working...";
string result = await Task<string>.Run(() => worker.GenerateAsciiHtml(bmp, pixels, manager.Size));
manager.HTML = result;
Zde je metoda v jiné třídě.
public string GenerateAsciiHtml(BitmapImage bmp, byte[] pixels, int size)
{
StringBuilder ascii = new StringBuilder();
ascii = new StringBuilder();
ascii.Append(string.Format("<body style=\"font-family: 'Courier New', Courier, monospace;font-size: {0}px;\">", 5));
for (int h = 0; h < bmp.PixelHeight - size; h += size)
{
for (int w = 0; w < bmp.PixelWidth - size; w += size)
{
Color color = bmp.GetPixel(pixels, w, h);
ascii.Append(string.Format("<span style='color:rgb({0},{1},{2});'>{3}{3}</span>",
color.R, color.G, color.B, getAsciiChar(color.A)));
}
ascii.Append("<br>");
}
ascii.Append("</body>");
return ascii.ToString();
}
Skončí to chybou ihned v cyklu.
The application called an interface that was marshalled for a different thread.
Nevíte kde je problém ? Vím že asi otravuju ale já už fakt nevím
Já si pořád myslím že to dělá ta knihovna třetích stran...
Už tma žádnou nepoužívám. GetPixel je moje vlastní metoda. Všechno už je klasicky součástí WinRT
Nechci ... btw zjistil
jsem následující. Že to volám z jiné třídy nevadí. Problém je v tom
předávání Bitmapy. TU si načtu ze souboru / vyfotím kamerou a načítám /
fotím ve stejné třídě jako volám tu metodu na generování. Poté to
vlastně padá kvůli tomu že se snažím asi přistoupit k něčemu co je z
jiného vlákna. Jak to vyřešit, nevíš ?
Tak zde radí toto http://stackoverflow.com/…ent-thread-i a zde to samý http://social.msdn.microsoft.com/…ca081921f79/ ale to zase zamrzne UI.
Už ale vím kde je problém. Ten error vyskočí vždy když se snažím editovat něco z UI Thread, teď to Image. Neívm jak udělat to aby nezmarzlo UI ale zároveň dostal tu Bitmapu ....
Možná zde existuje něco jako Invoke u vláken. Ale nevím.
A neslo by to, kdyby se ta bitmapa nejak naklonovala? Existuje metoda
MemberwiseClone(), ale nevim co presne dela
Zobrazeno 28 zpráv z 28.