Linq to XML w aplikacji WP

0

Witajcie,
Kiepski ze mnie programista, żeby nie powiedzieć ze żaden wiec proszę Was o pomoc.
Mam program który rozpoznaje kody kreskowe, korzysta z biblioteki ZXing. Wszystko działa jak należy, jednakże potrzebuje dodać funkcję rozpoznawania kodów. W tym celu doszedlem do "linq to xml" gdyż pamięć izolowana i localdb w WP 8.1 wydała mi się zbyt skomplikowana.

void cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
        {
         
            Dispatcher.BeginInvoke(() =>
            {
         
                //skanowanie
                //outputImg.Source = img;

                BitmapImage img = new BitmapImage();
                img.SetSource(e.ImageStream);
                WriteableBitmap barcodeBitmap = new WriteableBitmap(img);
                // create a barcode reader instance
                IBarcodeReader reader = new BarcodeReader();
                // detect and decode the barcode inside the bitmap
                var result = reader.Decode(barcodeBitmap);

 	  XElement xelement = XElement.Load("produkty.xml");
                //IEnumerable<XElement> produkty = xelement.Elements();
                var prod = from p in xelement.Descendants("PRODUKT")
                           where p.Element("ID").Value == result.Text
                           select p.Element("NAZWA").Value;
                foreach (var p in prod)

 		if (result != null)
               		 {
                   		 MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), 				System.Environment.NewLine, result.Text, System.Environment.NewLine, p ));
              		  }
                timer.Change(1000, 1000);
               
            });
        } 

W tym momencie powyższy kod nie wywala błędów ale także uniemożliwia pierwotne działanie aplikacji.
Zauważyłem także ze wywala mi wyjątek (zamieszczam w załączniku).
Wydaje mi się, że to on uniemożliwia mi w tym momencie wyświetlanie tych produktów.

Dodaje także mojego xml'a, jest to prosty składniowo plik, wstępnie nie będzie zawierał dużo danych.

<?xml version="1.0" encoding="UTF-8"?>
<!-- Edited by XMLSpy -->
<PRODUKTY>
	 <PRODUKT>
		<ID>9788372292704</ID>
		<NAZWA>Ksiazka</NAZWA>
 	</PRODUKT>
	 <PRODUKT>
		<ID>13124123</ID>
   	<NAZWA>Bob Dylan</NAZWA>
	</PRODUKT>
	 <PRODUKT>
    		<ID>2096000099067</ID>
   		<NAZWA>Kod kreskowy</NAZWA>
	</PRODUKT>
</PRODUKTY>
0

Zakomentowałem ta linijke System.Diagnostics.Debugger.Break();

 private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
               // System.Diagnostics.Debugger.Break();
            }
        }

i przy którymś break lub continue tego wyjątku wskazało mi na ten fragment

  where p.Element("ID").Value == result.Text

result.Text ponoć ma wartość null, ktoś wie dlaczego tak może sie dziać lub jak to wyeliminować?

Ewentualnie jakieś inne metody na wyciąganie nazwy produktu po kodzie kreskowym??

1

Sprawdzaj, czy result.Text nie jest nullem i dopiero wtedy próbuj wyszukiwać.

0

Jeju to takie oczywiste, wprawdzie musialem zrobic 3 podejscie do Twojej odpowiedzi ale załapałem i chodzi. Dziękuje

0

Mam jeszcze 1 mały mankament. Mianowicie gdy umiescilem kod "linq to xml" w tym ifie by pozbyc sie wartosci null w zmiennej result.text

  if (result != null)
       {
			XElement xelement = XElement.Load("produkty.xml")
                var prod = from p in xelement.Descendants("PRODUKT")
                           where p.Element("ID").Value == result.Text
                           select p.Element("NAZWA").Value;
                foreach (var p in prod)
                            MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(),                 System.Environment.NewLine, result.Text, System.Environment.NewLine, p ));
        }

to rozpozawany jest jedynie produkt zawarty w pliku xml. W innym wypadku aplikacja nie rozpoznaje kodu.
Kombinowalem na różne sposoby, m.in dodajac zmienna

var r = "nieznany produkt"; 

i tworzac cos takiego if (result != null)
{
XElement xelement = XElement.Load("produkty.xml");
var prod = from p in xelement.Descendants("PRODUKT")
where p.Element("ID").Value == result.Text
select p.Element("NAZWA").Value;
foreach (var p in prod)

                    if (p != null)
                    {
                        MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), System.Environment.NewLine, result.Text, System.Environment.NewLine, p));
                    }
                    else if (p == null)
                    {
                        MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), System.Environment.NewLine, result.Text, System.Environment.NewLine, r));
                    }

            }

Jednakże bez skutku. Domyślam sie iż if w ifie to blad (pewnie nawet karygodny) ale nie mam pojecia jak moglbym sprawdzac zmienna p, ktora zadeklarowana jest w tym pierwszym ifie.  Ktos moglby mnie naprowadzic?

Dodam iż nie moge brac pod uwage warunku 
```csharp
result ==  null

poniewaz najczesciej on bedzie wylapywany (chyba przez mankamenty biblioteki ZXing w C#, podobno kiepsko sie sprawdza)

0

Odświeżam temat ponieważ próbowałem już na n sposobów i nie umiem sobie poradzić.
Zmieniłem trochę strukturę xml:

<?xml version="1.0" encoding="UTF-8"?>
<PRODUKTY>
  <PRODUKT Nazwa="Ksiazka">
    <ID>9788372292704</ID>
  </PRODUKT>
  <PRODUKT Nazwa="Bob Dylan">
    <ID>13124123</ID>
  </PRODUKT>
  <PRODUKT Nazwa="Kodzik">
    <ID>5907134821257</ID>
  </PRODUKT>
</PRODUKTY>

i wczytuje go trochę inaczej (wydaje mi sie ze lepiej)

void cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
        {
            Dispatcher.BeginInvoke(() =>
            {
                BitmapImage img = new BitmapImage();
                img.SetSource(e.ImageStream);
                WriteableBitmap barcodeBitmap = new WriteableBitmap(img);
                // create a barcode reader instance
                IBarcodeReader reader = new BarcodeReader();
                // detect and decode the barcode inside the bitmap
                var result = reader.Decode(barcodeBitmap);
		var r = "nieznany produkt";

           if (result != null)
           {
               XElement xelement = XElement.Load("xml1.xml");
               IEnumerable<XElement> PRODUKTY =
                       from p in xelement.Elements("PRODUKT")
                       where (string)p.Element("ID").Value == result.Text
                       select p;
               foreach (XElement p in PRODUKTY)
              
                       if (p.Element("ID").IsEmpty == true)
                       {
                           MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), System.Environment.NewLine, result.Text, System.Environment.NewLine, r));
                       }
                       else 
                       {
                           MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), System.Environment.NewLine, result.Text, System.Environment.NewLine, p.Attribute("Nazwa").Value));
                       }
                   
           } 

jednak za żadne skarby nie moge osiagnac tego warunku

  if (p.Element("ID").IsEmpty == true)
                       {
                           MessageBox.Show(string.Format("Format: {0} {1} Content: {2} {3} Product: {4}", result.BarcodeFormat.ToString(), System.Environment.NewLine, result.Text, System.Environment.NewLine, r));
                       }

Próbowałem także uzyć takiego

if (p.Element("ID").Value != result.Text) 

oraz wielu innych i nadal to samo.
Nie wiem co jest nie tak bo program działa jeśli zczytywany produkt mam w pliku xml. Za chwile go usunę do testu i już wtedy nie rozpoznaje ( nie inicjuje dekodowania jakby albo nie wiem).

Pomożcie

0

Albo ja jestem ślepy albo ten warunek nigdy nie zostanie spełniony:

if (p.Element("ID").IsEmpty == true)

a ten to już na pewno:

if (p.Element("ID").Value != result.Text) 
0

Ale jeśli mam to ograniczenie

 where (string)p.Element("ID").Value == result.Text

top.Element("ID")

nigdy nie będzie pusty? Myślałem ze jeśli sczytany kod jest o takim id jak w pliku to wtedy p jest, jeśli nie to jest puste.

Ktoś ma pomysł jak mógłby w takim razie brzmieć warunek, który odróżni mi kod z result od tych umieszczonych w pliku?
0

Skoro mają być inne niż w result.Text to warunek powinien wyglądać następująco:

IEnumerable<XElement> PRODUKTY =
  from p in xelement.Elements("PRODUKT")
  let xId = p.Element("ID")
  where xId != null && xId.Value != result.Text
  select p;

no chyba że ja źle zrozumiałem co chcesz osiągnąć.

0

Ta biblioteka, która rozpoznaje mi kody wypluwa po prostu format kodu czyli np : EAN13, Content czyli własnie ten kod no i dodałem Product żeby tam wrzucać nazwę produktu (którego znam czyli mam w pliku xml)

Założenie mojej aplikacji to używanie tego Barcode Readera do skanowania produktów, dlatego jeśli skanuje produkt i wprowadziłem już go do bazy(xml) to wyciąga mi nazwę tegoż produktu, jeśli zeskanowany kod nie znajduje się w pliku to wypluwa "nieznany produkt".
W tym momencie nie rozumiem właśnie dlaczego jeśli produktu nie było w bazie to nie mogłem nic osiągnąć.
Zrobiłem break'a i screena w momencie sczytywania produktu którego nie ma w bazie, może Ty coś poradzisz bo mi za wiele nie pomaga. f66f77fe03.png
Result na nim jest jak widać, jednak biblioteka go odczytuje. Czy można w tym zapytaniu odpytywać xml o zmienne pasujace do result.Text i zmienna nie pasujące?
A potem dodać ten warunek

  if (p.Element("ID").IsEmpty == false)
{// kod wypluwajacy "nieznany produkt"}
 if (k.Element("ID").IsEmpty == false) 
{//kod wypluwający nazwę produktu}

Użyłem wcześniej własnie tego warunku

 if (p.Element("ID").IsEmpty == true) 

i tutaj wypluwa nieznany produkt a w else żeby wyciągało mi produkt dlatego, że chciałem właśnie coś takiego osiągnąć jak opisałem wyżej. Pewnie to kwestia zapytania linq to xml, którego niestety nie ogarniam już bardziej.

Edit: Już łapie, nie tworzy mi w ogóle zmiennej p jeśli nie ma danego kodu w pliku. To teraz mam pytanie jak wywołać mojego message boxa jeśli nie ma zmiennej, da się takie coś wykombinować?

1

Result na nim jest jak widać, jednak biblioteka go odczytuje. Czy można w tym zapytaniu odpytywać xml o zmienne pasujace do result.Text i zmienna nie pasujące?

Czyli po prostu chcesz wszystkie:

IEnumerable<XElement> PRODUKTY =
  from p in xelement.Elements("PRODUKT")
  select p;

A później tylko pętla:

foreach (XElement p in PRODUKTY)
{
	var xId = p.Element("ID");
	if (xId != null)
	{
		if (xId .IsEmpty)
		{
			// "nieznany produkt"
		}
		else if(xId .Value == result.Text)
		{
			// p.Attribute("Nazwa").Value;
		}
	}
	else
	{
		// A jak jest null to coś...
	}
}

Btw. popracuj nad nazywaniem zmiennych po podczas kopiuj wklej kodu z twojego postu już powoli zaczynałem się gubić. :D

0

Dziękuję że poświęcasz swój czas i za inne spojrzenie na to zapytanie xml. Efekt jest jak poprzednio. Produkt wprowadzony daje ładny msgbox, produkt nie wprowadzony, nie daje nic.

Zrobiłem break by się co nieco dowiedzieć i mam coś takiego:8218023b2b.png
W ta zmienną xId pakuje pierwszy element z xml'aZmienna p ma wartość pierwszego elementu z xml'a i warunek

  if (xId.IsEmpty)

nigdy nie jest pusty.

Dla porównania break w przypadku ksiazki której kod jest w pliku xml:1218009d7f.png
Kiedy nie mam produktu w xml'u to pobiera jako p pierwszy element, a jak produkt jest to kod działa wyśmienicie.

Pierw myślałem, że sczytana wcześniej książka ładuje się do tej zmiennej ale specjalnie zamieniłem kolejność na Boba i ewidentnie pierwszy rekord z xml'a wrzuca do tej p

<?xml version="1.0" encoding="UTF-8"?>
<PRODUKTY>
  <PRODUKT Nazwa="Bob Dylan">
    <ID>13124123</ID>
  </PRODUKT>
  <PRODUKT Nazwa="Ksiazka">
    <ID>9788372292704</ID>
  </PRODUKT>
  <PRODUKT Nazwa="Kodzik">
    <ID>5907134821257</ID>
  </PRODUKT>
<PRODUKT Nazwa="Czekolada">
  <ID>5901588017785</ID>
</PRODUKT>
</PRODUKTY>

Ps. Wybacz, takie mi zmienne przyszly do głowy, a że to mój pierwszy program to nie mam jeszcze wypracowanej kultury programowania :P
Żebyś zobaczył ile mam zakomentowanego kodu, który mi ewoluowal po wszystkich moich próbach i który trzymam jakbym chcial do niego wrócić :D

Wersja 2
Chciałem trochę na dziko zrobić to tak:
Zmieniłem ten pierwszy rekord do postaci

  <PRODUKT Nazwa="Bob Dylan">
    <ID>1</ID>
  </PRODUKT>

Ifa zmieniłem na taki:

foreach (XElement p in PRODUKTY)
                    {
                        var xId = p.Element("ID");
                        if (xId != null)
                        {
                            if (xId.Value=="1")
                            {
                                 // "nieznany produkt"
                            }
                            else if (xId.Value == result.Text)
                            {
                                // p.Attribute("Nazwa").Value;
                            }
                        }
                        else
                        {
                            
                        }
                    } 

iii...
Nieznany produkt sczytuje ładnie, natomiast produkt z xml'a wypluwa następująco:
realizuje pierwszego ifa (msgbox z nieznanym produktem) a potem drugiego (właściwy msgbox z odczytanym produktem)

EDIT:
Dzięki raz jeszcze za ten kodzik, udało mi się osiągnąć cel.

1 użytkowników online, w tym zalogowanych: 0, gości: 1