Christian Wagnsonner

Published: 79 articles

WP8 – IsOnline – Prüfen der Internet Connection

Hallo Leute,

nachstehend ein einfaches Code-Snippet, wie man auf einem WP8-Device prüfen kann, ob das Gerät online oder offline ist.

public static bool IsOnline()
        {
            return (Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType != Microsoft.Phone.Net.NetworkInformation.NetworkInterfaceType.None);
        }

In meiner App, prüfe ich zudem, ob ein Webservice erreichbar ist und zeige den Status über den Systray an:

/// <summary>
        /// Determines whether [is address available] [the specified callback action].
        /// </summary>
        /// <param name="callbackAction">The callback action.</param>
        public void IsOnline(Action<bool> callbackAction)
        {
            try
            {
                if (!utils.Connection.IsOnline())
                    if (callbackAction != null)
                        callbackAction(false);

                var login = new Benutzer() { Name = "login", Password = "login" };
                Helper.JsonHelper.DoRestGetOperation(login, "benutzer/UAP", response =>
                {
                    if (response.StatusCode == HttpStatusCode.BadGateway ||
                        response.StatusCode == HttpStatusCode.BadRequest ||
                        response.StatusCode == HttpStatusCode.Conflict ||
                        response.StatusCode == HttpStatusCode.ExpectationFailed ||
                        response.StatusCode == HttpStatusCode.Forbidden ||
                        response.StatusCode == HttpStatusCode.GatewayTimeout ||
                        response.StatusCode == HttpStatusCode.HttpVersionNotSupported ||
                        response.StatusCode == HttpStatusCode.LengthRequired ||
                        response.StatusCode == HttpStatusCode.NotFound ||
                        response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired ||
                        response.StatusCode == HttpStatusCode.RequestTimeout ||
                        response.StatusCode == HttpStatusCode.RequestUriTooLong ||
                        response.StatusCode == HttpStatusCode.ServiceUnavailable)
                    {
                        if (callbackAction != null)
                        {
                            callbackAction(false);
                            return;
                        }

                    }
                    if (callbackAction != null)
                        callbackAction(true);

                });

            }
            catch
            {
                if (callbackAction != null)
                    callbackAction(false);
            }
        }

Im OnNavigatedTo einer App-Page rufe ich die Methode dann wie folgt auf:

App.BoContext.IsOnline(b =>
            {
                try
                {
                    if (b)
                    {
                        ShowProgressIndicatorAndHideInSeconds("Online", 2, Colors.Green);
                        lineConnectionState.Background = new SolidColorBrush(Colors.Green);
                    }
                    else
                    {
                        ShowProgressIndicatorAndHideInSeconds("Offline", 2, Colors.Red);
                        lineConnectionState.Background = new SolidColorBrush(Colors.Red);
                    }
                }
                catch (Exception)
                {
                    throw;
                }
            });

Kurze Anmerkung: lineConnectionState ist ein Grid-Control mit 2px Höhe, welchem ich einfach die Background-Farbe ändere.

Cheers,
Christian

WP8 – Sounddatei abspielen – MediaElement

Hallo Leute,

heute will ich euch kurz zeigen, wie man eine Sounddatei (z.B. WAV) abspielt. Dafür bedarf es nur weniger Zeilen Code bzw. XAML.

Zunächst fügt einer App-Page einen Button hinzu, und platziert am einfachsten direkt daneben ein Element vom Typ „MediaElement“:

<Button Background="Red"  Grid.Column="1" x:Name="btnDecline" Content="Ablehnen"></Button>
<MediaElement Grid.Column="1" x:Name="mediaPlayer"></MediaElement>

Subscribed dem Click-Event eures Buttons und fügt folgende Zeilen Code hinzu:


void btnDecline_Click(object sender, RoutedEventArgs e)
        {
            mediaPlayer.Source = new Uri("/Assets/Audio/error.wav", UriKind.Relative);
            mediaPlayer.MediaEnded += mediaPlayer_MediaEnded_Decline;
            mediaPlayer.Play();
        }

        void mediaPlayer_MediaEnded_Decline(object sender, RoutedEventArgs e)
        {
            App.Navigation.Redirect(Redirection.Sites.Main);
        }

Nun wird die WAV-Datei im Klick-Event des Buttons ausgeführt. Achtet auf die Subscription auf „MediaEnded“. In meinem Fall will ich direkt, nachdem die Datei abgespielt wurde, auf meine Main-Seite zurückspringen. Würde ich das nicht im „MediaEnded“-Event machen, würde die Datei nicht (oder nicht fertig) abgespielt werden.

Cheers,
Chris

WP8 – TaskScheduler – Aufgaben in periodischen Abständen erledigen

Hallo Leute,

mit diesem Blog-Eintrag möchte ich euch zeigen, wie Ihr einen TaskScheduler hinzufügen könnt. Im konkreten Beispiel möchte ich für eine DB-Abfrage die in meinem letzten Blog-Eintrag erzeugte IconicTile aktualisieren.

An dieser Stelle möchte ich mich wieder einmal bei Channel9 bedanken, welcher einen hervorragenden Video-Blog zu diesem Thema verfasst hat.

Zunächst einmal muss man verstehen, dass ein TaskScheduler/Background Agent eine eigene, eingeschränkte App ist, welche auch dann läuft, wenn die App selbst nicht läuft! Ein Scheduled Task bleibt für ca. 2 Wochen „aktiv“, bevor er vom System entfernt wird. Schlägt der Task zwei Mal fehl, wird er ebenfalls vom System entfernt. Das bedeutet für uns, dass wir den Task immer wieder hinzufügen müssen, z.B. beim Aufrufen des Hauptmenüs oder der Startseite der App. Man kann natürlich auch einem Event wie z.B. Application_Launching subscriben.

Als erstes muss man mal ein neues Projekt seiner Solution hinzufügen. Visual Studio bietet hier die Vorlage „Windows Phone Schedules Task Agent“ an:

2013-12-10 11_10_31-New Project

Dieses neue Projekt enthält nun eine Klasse, die ScheduledAgent.cs. Diese Klasse kann im Großen und Ganzen unverändert bleiben, interessant für uns ist lediglich die „OnInvoke“ Methode.

 protected async override void OnInvoke(ScheduledTask task)
        {
            try
            {
                // TODO: Your code
                NotifyComplete();
            }
            catch (Exception)
            {
                Abort();
                throw;
            }
        }

Wichtig ist hier, dass jeder erfolgreiche Task zum Abschluss die „NotifyComplete()“ Methode aufruft, da sich der Task sonst nicht beendet und der nächste Intervall niemals schlagend wird. Im Fehlerfall gilt das selbe für „Abort()“. Achten sollte man auch auf das „async“ Keyword. Alle eigenen Methodenaufrufe müssen ebenfalls asynchron sein.

Doch zuerst muss man der eigenen (Haupt-)App mitteilen, dass es den neuen TaskScheduler überhaupt gibt und Tasks erzeugen. Dafür öffnet man die WMAppManifest.xml im XML-Editor. Sucht die Node „Tasks“ und fügt einen ExtendedTask hinzu:

<Tasks>
      <DefaultTask Name="_default" NavigationPage="xxx.xaml" />
      <ExtendedTask Name="BackgroundTask">
        <BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="PeriodicAgent" Source="namespace" Type="namespace.ScheduledAgent" />
      </ExtendedTask>
    </Tasks>

Ersetzt bitte „namespace“ mit dem Namespace eures TaskSchedulers. Als nächste fügt eurer App eine Referenz auf das TaskScheduler Projekt hinzu (Rechtsklick auf References -> Add Reference -> Solution).

Ist das erledigt, können wir uns auf das Erzeugen von Tasks konzentrieren. Ich habe dafür meiner App.xaml.cs eine Methode „StartPeriodicAgent()“ hinzugefügt:

 /// <summary>
        /// Starts the periodic agent.
        /// </summary>
        public static void StartPeriodicAgent()
        {
            string taskName = "BackgroundTask";
            PeriodicTask oldTastk = ScheduledActionService.Find(taskName) as PeriodicTask;

            if (oldTastk != null)
            {
                ScheduledActionService.Remove(taskName);
            }

            PeriodicTask task = new PeriodicTask(taskName);
            task.Description = "Aktualisiert die App-Kachel für offene/genehmigte Urlaube.";

            ScheduledActionService.Add(task);

            if(Debugger.IsAttached)
                ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
            
        }

Wichtig ist hier, dass der TaskName der gleiche ist, wie vorhin in der WMAppManifext.xml. Dadurch wird der Anwendung klargemacht, dass der eigene TaskScheduler verwendet werden muss. Der restliche Code ist eigentlich selbsterklärend. Erwähnenswert sind vielleicht die letzten zwei Zeilen, welche den Effekt haben, dass der Task nach 30 Sekunden und nicht erst nach ca. 30 Minuten aufgerufen wird. Diese Methode ist lt. Microsoft lediglich für Debugging-Zwecke gedacht – daher die vorhergehende If-Condition.

Diese Methode könnt Ihr z.B. in Konstruktor der App.xaml.cs aufrufen.

Nun springen wir zurück zur ScheduledAgent.cs, zur Methode OnInvoke. Ich rufe hier die Methode UpdateMainTile auf, um eine IconicTile (Kachel) zu aktualisieren:

 protected async override void OnInvoke(ScheduledTask task)
        {
            try
            {
                await Tile.UpdateMainTile(5); // TODO: Eigene Methode zum Berechnen des Counts verwenden!

                if (Debugger.IsAttached)
                    ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(30));
                
                NotifyComplete();
            }
            catch (Exception)
            {
                Abort();
                throw;
            }
        }

Wichtig ist hier das „await“-Keword vorm Aufruf von UpdateMainTile(). Auch auf der Methode selbst ist noch etwas zu ergänzen, denn auch diese muss klarerweise async und vom Typ „Task“ sein:

 public async static Task UpdateMainTile(string title, int count)
        {
            await Task.Factory.StartNew(() =>
            {
                //Get application's main tile
                var mainTile = ShellTile.ActiveTiles.FirstOrDefault();


                if (null != mainTile)
                {
                    IconicTileData tileData = new IconicTileData()
                    {
                        Count = count,
                        BackgroundColor = Color.FromArgb(0, 151, 193, 1),
                        Title = title,
                        IconImage = new Uri("/Assets/Tiles/IconicTileMediumLarge.png", UriKind.RelativeOrAbsolute),
                        SmallIconImage = new Uri("/Assets/IconicTileSmall.png", UriKind.RelativeOrAbsolute),
                        WideContent1 = "urlaube in genehmigung",
                    };

                    mainTile.Update(tileData);
                }

            });
        }

Um nicht zuviel Code umstellen zu müssen, kann man auch einfach mit await Task.Factory.StartNew() arbeiten. Wichtig ist jedenfalls, dass sämtliche aufgerufenen Methoden „async“ und vom Typ „Task“ sind.

Cheers,
Christian

WP8 – Dynamische Kachel gestalten – PeriodicTile hinzufügen

Hallo Leute,

heute möchte ich euch zeigen, wie Ihr ganz einfach einen sogenannten „PeriodicTile“ hinzufügen könnt.
Vorweg sei gesagt, dass es prinzipiell folgende Arten von Tiles gibt:

  • Flip Tile
  • Iconic Tile
  • Cycle Tile

Vielleicht kommen zu einem späteren Zeitpunkt noch Blog Einträge zu den anderen Tile-Arten. Hier soll es jetzt, wie gesagt, um den Iconic-Tile gehen.

iconic

 

Der Iconic-Tile bietet alle drei unterstützen Tile-Größen (Small, Medium & Large) an.

Zu allererst muss man im WP8-Projekt in das WMAppManifest.xml gehen. Und dort die Unterstützung für Tiles aktivieren:

iconic_wma

 

In meinem Beispiel möchte ich nur die Größen Small und Medium unterstützen und  habe dafür die entsprechenden Grafiken hinterlegt. Die Abmessungen der Grafiken entnehmt bitte nachfolgendem Screenshot. Hält man sich nicht daran, gibt’s nachher verwaschene Tiles, was ich sehr unhübsch finde.

tile_sizes

 

Nun zum programmatischen Teil der Geschichte.

/// <summary>
        /// Updates the main tile.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="count">The count.</param>
        public async static Task UpdateMainTile(string title, int count)
        {
            await Task.Factory.StartNew(() =>
            {
                //Get application's main tile
                var mainTile = ShellTile.ActiveTiles.FirstOrDefault();


                if (null != mainTile)
                {
                    IconicTileData tileData = new IconicTileData()
                    {
                        Count = count,
                        BackgroundColor = Color.FromArgb(0, 151, 193, 1),
                        Title = title,
                        IconImage = new Uri("/Assets/Tiles/IconicTileMediumLarge.png", UriKind.RelativeOrAbsolute),
                        SmallIconImage = new Uri("/Assets/IconicTileSmall.png", UriKind.RelativeOrAbsolute),
                        WideContent1 = "urlaube in genehmigung",
                    };

                    mainTile.Update(tileData);
                }

            });
        }

In meinem Beispiel möchte ich ein möglicherweise bereits existierendes Tile aktualisieren, keine neuen (oder weiteren) Tiles hinzufügen. Sofern ein Tilevorhanden ist (mainTile != null), erzeuge ich ein neues IconicTileData Objekt, welches ein paar Eigenschaften besitzt, am interessantesten ist bei einem IconicTile natürlich der Count. Aber auch die anderen Properties möchte ich kurz erklären:

iconic_desc

Viel Spaß beim nachmachen.

Cheers,
Chris

WP8 – SQL Ce – Linq2Sql – CodeFirst Approach – Relationen abbilden (1:n)

Hallo Leute,

quasi als Fortsetzung zu meinem letzten Blogeintrag (WP8 – SQL Ce – Linq2Sql) möchte ich euch zeigen, wie Ihr eine 1:n Relation abbilden könnt. Das ist leider gar nicht so einfach, vor allem wenn man auch DataBindings unterstützen möchte.

Für unser Beispiel nehmen wir einfach zwei Tabellen an: Mitarbeiter (n) und Abteilung (1).

Mitarbeiter
* Id (int) – PK
* Nachname (nvarchar(255))
* AbteilungId (int) – Fremdschlüssel

Abteilung
* Id (int) – PK
* Name (nvarchar(255))

Als ersten Schritt muss man nun der N-Seite eine sog. EntityReference hinzufügen. Das nachfolgende Codestück zeigt die Klasse Mitarbeiter, mit den drei Columns/Properties, angereichert mit den notwenigen Erweiterungen für die EntityReference:

[Table(Name = "Mitarbeiter")]
    public class Mitarbeiter : Base
    {
        public Mitarbeiter()
        {
		    // EntityReference
            this._Abteilung = default(EntityRef<Abteilung>);            
        }

        #region identity column for all tables
        private int _id = -1;
        [Column(Storage = "Id", DbType = "int IDENTITY(1,1) NOT NULL", IsPrimaryKey = true, IsDbGenerated = true)]
        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    NotifyPropertyChanging();
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }
        #endregion

        
        private string _Nachname;
        [Column(Storage = "Nachname", DbType = "NVarChar(255) NOT NULL")]
        public string Nachname
        {
            get
            {
                return _Nachname;
            }
            set
            {
                if (value != _Nachname)
                {
                    _Nachname = value;
                    NotifyPropertyChanged("Nachname");
                }
            }
        }

        

        private int _AbteilungId;
        [Column(Storage = "AbteilungId", DbType = "int DEFAULT NULL")]
        public int AbteilungId
        {
            get
            {
                return _AbteilungId;
            }
            set
            {
                if (value != _AbteilungId)
                {
                    if (this._Abteilung.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                   
                    NotifyPropertyChanging();
                    _AbteilungId = value;
                    NotifyPropertyChanged("AbteilungId");
                }
            }
        }

        private EntityRef<Abteilung> _Abteilung;
        [Association(Name = "Mitarbeiter_Abteilung", Storage = "_Abteilung", ThisKey = "AbteilungId", OtherKey = "Id", IsForeignKey = true)]
        public Abteilung Abteilung
        {
            get
            {
                return this._Abteilung.Entity;
            }
            set
            {
                //.. TODO
            }
        }      

    }

Beachtet dabei, dass man im Konstruktor der Klasse die Variable _Abteilung instanzieren muss! Weiter unten, beim Property „Abteilung“, muss ein Association-Attribut hinzugefügt werden. Wir sind auf der N-Seite, bedeutet, dass ein Mitarbeiter nur EINE Abteilung besitzen kann, deshalb werden hier keine Collections oder dgl. verwendet.

Betrachtet man das Association-Attribut genauer, gibt es folgendes zu wissen:

[Association(Name = "Mitarbeiter_Abteilung", Storage = "_Abteilung", ThisKey = "AbteilungId", OtherKey = "Id", IsForeignKey = true)]

* Storeage… ist keine Spalte, welche in einer Tabelle verwendet wird, ist viel mehr für das Databinding notwendig
* ThisKey… Wir sind auf der N-Seite, es ist also der Foreign-Key anzugeben
* OtherKey… Primärschlüssel der 1-Seite
* IsForeignKey… Selbstredend…

Nun wollen wir den Setter des Properties fertigstellen:

private EntityRef<Abteilung> _Abteilung;
[Association(Name = "Mitarbeiter_Abteilung", Storage = "_Abteilung", ThisKey = "AbteilungId", OtherKey = "Id", IsForeignKey = true)]
public Abteilung Abteilung
{
	get
	{
		return this._Abteilung.Entity;
	}
	set
	{
		Abteilung previousValue = this._Abteilung.Entity;
		if (((previousValue != value) || (this._Abteilung.HasLoadedOrAssignedValue == false)))
		{
			NotifyPropertyChanging();
			if ((previousValue != null))
			{
				this._Abteilung.Entity = null;
				previousValue.Mitarbeiter.Remove(this);
			}
			this._Abteilung.Entity = value;
			if ((value != null))
			{
				value.Mitarbeiter.Add(this);
				this._AbteilungId = value.Id;
			}
			else
			{
				this._AbteilungId = -1;
			}
			NotifyPropertyChanged("Abteilung");
		}
	}
}

Um das Property „Abteilung“ später beim Databinding verwenden zu können, ist der Aufruf der Methoden NotifyPropertyChanged() und NotifyPropertyChanging() empfehlenswert (in meinem letzten Blogeintrag habe ich euch gezeigt, dass meine Base-Klasse von den Interfaces INotifyPropertyChanged und INotifyPropertyChanging ableitet).

Zudem seht Ihr, dass der ForeignKey (das Property „this._AbteilungId“) entsprechend gesetzt wird. Der Rest des Codes wird klar, sobald wir uns die 1-Seite, also die Tabelle Abteilung, angesehen haben.

Der Klasse Abteilung muss das Gegenstück zur EntityReference, nämlich das sog. EntitySet, hinzugefügt werden. Das nachfolgende Codebeispiel zeigt die Klasse Abteilung mit der Erweiterung.

[Table(Name = "ORG_ABTEILUNG")]
public class Abteilung : Model.Base
{
	public Abteilung()
	{
		this._mitarbeiter = new EntitySet<Mitarbeiter>(new Action<Mitarbeiter>(this.attach_Mitarbeiter), new Action<Mitarbeiter>(this.detach_Mitarbeiter));
	}

	private int _id = -1;
	[Column(Storage = "Id", DbType = "int IDENTITY(1,1) NOT NULL", IsPrimaryKey = true, IsDbGenerated = true)]
	public int Id
	{
		get
		{
			return _id;
		}
		set
		{
			if (value != _id)
			{
				NotifyPropertyChanging();
				_id = value;
				NotifyPropertyChanged("Id");
			}
		}
	}
	
	private string _Name;
	[Column(Storage = "Name", DbType = "NVarChar(255) NOT NULL")]
	public string Name
	{
		get
		{
			return _Name;
		}
		set
		{
			if (value != _Name)
			{
				NotifyPropertyChanging();
				_Name = value;
				NotifyPropertyChanged("Name");
			}
		}
	}

   
	#region Reference Mitarbeiter n:1 Abteilung
	private EntitySet<Mitarbeiter> _mitarbeiter;
	[Association(Name = "Mitarbeiter_Abteilung", Storage = "_mitarbeiter", ThisKey = "Id", OtherKey = "AbteilungId", DeleteRule = "NO ACTION")]
	public EntitySet<Mitarbeiter> Mitarbeiter
	{
		get
		{
			return this._mitarbeiter;
		}
		set
		{
			this._mitarbeiter.Assign(value);
		}
	}

	private void attach_Mitarbeiter(Mitarbeiter entity)
	{
		NotifyPropertyChanging();
		entity.Abteilung = this;
	}

	private void detach_Mitarbeiter(Mitarbeiter entity)
	{
		NotifyPropertyChanging();
		entity.Abteilung = null;
	}
	#endregion
}

Wir Ihr seht, wird im Konstruktur die Variable _mitarbeiter instanziert. Dabei wird dieser Variable ein neues EntitySet zugewiesen, welches die Actions „onAdd“ (attach_Mitarbeiter) und „onRemove“ (detach_Mitarbeiter) setzt. Das Property „Mitarbeiter“ ist klarerweise eine Collection (EntitySet), da eine Abteilung ja mehreren Mitarbeitern zugewiesen werden kann.

Betrachtet man jetzt nochmal das Property Abteilung der Klasse Mitarbeiter genauer, sieht man, dass auf das eben erzeugte Property Mitarbeiter der Klasse abteilung zugegriffen wird (value.Mitarbeiter.Add bzw. previousValue.Mitarbeiter.Remove). Dieses Add und Remove triggert die beiden Actions, welche wir vorhin definiert haben (detach_Mitarbeiter, attach_Mitarbeiter).

Somit ist sichergestellt, dass beide Seiten bei einer Veränderung diese Änderung auch mitbekommen und das (in weiterer Folge mögliche) Databinding auch immer noch korrekt ist.

Cheers,
Christian

WP8 – SQL Ce – Linq2Sql – CodeFirst Approach

Hallo Leute,

nachdem die ersten Erfahrungen mit SQLite nicht wirklich erfolgreich waren (keine Relationen supported, etc.), haben wir das DB-Modell auf SQLCe umgebaut und haben dabei den Microsoft „Code First“-Approach verfolgt.

Prinzipiell ist es ja recht einfach, man muss nur die eine oder andere Klasse erzeugen und diese mit Attributen verzieren. Beispiel:

[Table(Name = "TABELLENNAME")]
    public class Tabellenname : Base
    {

        private int _id = -1;
        [Column(Storage = "Id", DbType = "int IDENTITY(1,1) NOT NULL", IsPrimaryKey = true, IsDbGenerated = true)]
        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    NotifyPropertyChanging();
                    _id = value;
                    NotifyPropertyChanged("Id");
                }
            }
        }        
    }

Wir Ihr seht, leite ich von „Base“ ab. Das könnt Ihr getrost ignorieren, meine Base-Klasse leitet im lediglich von INotifyPropertyChanged und INotifyPropertyChanging ab und implementiert deren Methoden (NotifiyPropertyChanging() bzw. NotifyPropertyChanged()). Damit ist die Klasse auch gleich tauglich für ein mögliches DataBinding …

Spannender wirds im Attribut der Eigenschaft „Id“

[Column(Storage = "Id", DbType = "int IDENTITY(1,1) NOT NULL", IsPrimaryKey = true, IsDbGenerated = true)]

Storage… So heißt die Spalte in der Datenbank-Tabelle
DbType… Datentyp der Spalte, in diesem Fall als Autoincrement
IsPrimaryKey… Klare Sache, die ID soll Primärschlüssel sein
IsDbGenerated… Wichtig wenn Ihr ein AutoIncrement verwendet, teilt Linq2Sql mit, dass dieser Wert nicht in die DB geschrieben werden soll

Nun benötigt Ihr einen DataContext, welchem Ihr diese Tabelle zuordnet. Ich habe dafür die Klasse „DataContextBase“ geschaffen, welche von System.Data.Linq.DataContext ableitet.

 public partial class DataContextBase : System.Data.Linq.DataContext
    {
        private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();

        #region Extensibility Method Definitions
        partial void OnCreated();

        #endregion

        public DataContextBase(string connection) : base(connection, mappingSource)
        {
            OnCreated();
        }

        public DataContextBase(string connection,
            System.Data.Linq.Mapping.MappingSource mappingSource) :
                base(connection, mappingSource)
        {
            OnCreated();
        }

        #region Tables
        public System.Data.Linq.Table<Tabellenname> Tabellenname
        {
            get
            {
                return this.GetTable<Tabellenname>();
            }
        }

        

        #endregion
    }

Abschließend müsst Ihr den DataContext noch in der App.xaml.cs „registrieren“. Dafür bedarf es mehrerer Schritte.

1.) Deklarieren von Events, Konstanten und Eigenschaften:

public partial class App : Application
    {
        public const string DatabaseFilename = "isostore:vacation.sdf";
        public static string DatabasePassword = "";

        // Data Context
        public static DataContextBase YourDc { get; set; }

// ...
// ...
// ...
// ...
}

Im Konstruktor müsst Ihr euren DataContext noch intialisieren…

public App()
        {
// ...
// ...
// ...
            YourDc = new DataContextBase("Data Source='" + DatabaseFilename + "'" + (DatabasePassword.Length == 0 ? "" : ";Password='" + DatabasePassword + "'"));
            YourDc.ObjectTrackingEnabled = true;
        }

Abschließend müsst Ihr eurem DataContext natürlich noch mitteilen, dass die DB-Tabellen erzeugt werden sollen und evtl. ein paar System Daten erstellen..

Dafür habe ich drei Methoden erzeugt, welche ich in eine eigene DataHelper-Klasse ausgelagert habe:

 public static void InitializeDatabase(bool wipe, DataContextBase todo)
        {
            using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (wipe)
                    WipeDatabase(iso);
                else
                {
                    if (iso.FileExists(DbName))
                        return;
                }

                CreateDatabase(todo);
            }
        }
private static void CreateDatabase(DataContextBase context)
        {
            try
            {
                // Generate the database (with structure) from the code-based data context
                context.CreateDatabase();

                // Populate the database with system data
                //Task items = new Task();
                //items.Id = Guid.NewGuid();
                //items.Title = "Welcome to the \"Todo\"!";
                //items.LocationID = new Guid(Utils.LocationIDDefault);
                //items.Completed = true;
                //context.Items.InsertOnSubmit(items);

                //context.SubmitChanges();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error while creating the DB: " + ex.Message);
                System.Diagnostics.Debug.WriteLine("Error while creating the DB: " + ex.Message);
            }

        }
        
        public static void WipeDatabase(IsolatedStorageFile iso)
        {
            if (iso.FileExists(DbName))
                iso.DeleteFile(DbName);
        }

Cheers,
Christian

WP8 – Loading Spinner / Progress Indicator verwenden

Hallo Leute,

heute will ich euch ein einfaches Beispiel zeigen, wie man den ProgressIndicator bei WP8 verwenden kann.
An dieser Stelle ein Dankeschön an Channel9, welche das recht einfach beschrieben haben.

Der ProgressIndicator ist Teil des SystemTrays. Den SystemTray kann man wiederrum ein- und ausblenden. Achtet darauf in eurer App oder baut eure Methode so, dass der SystemTray richtig ein- bzw. ausgeblendet wird.

<phone:PhoneApplicationPage
    x:Class="xxxx"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:appBarUtils="clr-namespace:AppBarUtils;assembly=AppBarUtils"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d"
    shell:SystemTray.IsVisible="True"> <!-- TRAY EIN-/AUSBLENDEN -->

Kommen wir zur eigentlichen Methode. Diese ist recht simpel gehalten:

 /// <summary>
        /// Sets the prograss indicator.
        /// </summary>
        /// <param name="isVisible">if set to <c>true</c> [is visible].</param>
        private static void SetPrograssIndicator(bool isVisible, string text = "")
        {
            if(SystemTray.ProgressIndicator == null)
                SystemTray.ProgressIndicator = new ProgressIndicator();

            SystemTray.ProgressIndicator.IsIndeterminate = isVisible;
            SystemTray.ProgressIndicator.IsVisible = isVisible;
            SystemTray.ProgressIndicator.Text = text;
        }

Diese könnt Ihr nun ganz einfach aufrufen:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
SetPrograssIndicator(true, "Loading Data...");
// do something...
SetPrograssIndicator(false);
}

Herauskommen sollte dann folgendes:

2013-11-28 09_45_10-Neuen Beitrag erstellen ‹ wagnsonner.com — WordPress

Cheers,
Christian

WP8 – Kalendereintrag hinzufügen – Create Appointment

Hallo Leute,

unter WP8 ist es relativ einfach einen Kalendereintrag hinzuzufügen. Leider geht das nicht „im Hintergrund“, sondern man muss einen sogenannten „Launcher“ verwenden. Dieser Launcher leitet dann den Anwender direkt in die Kalender-App weiter, direkt in die Maske um einen neuen Eintrag anzulegen. Das geschieht lt. Microsoft aus Sicherheitsgründen.

Leider ist es infolgedessen nicht möglich einen Kalendereintrag programmatisch zu editieren. Mag sein, dass es dafür irgendeine API gibt, das Grundproblem ist, dass die der Launcher-Task keine ID o.ä. retourniert. Man erfährt auch nicht, ob der Anwender den Kalendereintrag überhaupt abgespeichert hat. Seht selbst:

SaveAppointmentTask saveAppointmentTask = new SaveAppointmentTask();

saveAppointmentTask.StartTime = DateTime.Now.AddHours(2);
saveAppointmentTask.EndTime = DateTime.Now.AddHours(3);
saveAppointmentTask.Subject = "Appointment subject";
saveAppointmentTask.Location = "Appointment location";
saveAppointmentTask.Details = "Appointment details";
saveAppointmentTask.IsAllDayEvent = false;
saveAppointmentTask.Reminder = Reminder.FifteenMinutes;
saveAppointmentTask.AppointmentStatus = Microsoft.Phone.UserData.AppointmentStatus.Busy;

saveAppointmentTask.Show(); // VOID - no return value

Ansonsten funktioniert dieser Launcher sehr bequem und ist flott implementiert. Auf der aufgehenden Seite (siehe Screenshot) werden alle mitgegebenen Properties entsprechend gesetzt und die Auswahl des Kalenders ist möglich.

new_appointment

Cheers,
Christian

WP8 – Verwenden von SQLite

Hallo Leute,

nachdem Ihr SQLite erfolgreich eingerichtet habt (siehe meinen Blog-Eintrag ), zeige ich euch hier, wie man SQLite im WP8-Projekt selbst verwendet, Tabellen erstellt, usw.

DB Connection einrichten

Am einfachsten geht’s wenn man in der App.xaml.cs die Initialisierung vornimmt, am besten im Konstruktor, unterhalb der üblichen Initialize-Methoden.


/// <summary>
        /// Constructor for the Application object.
        /// </summary>
        public App()
        {
            // Global handler for uncaught exceptions.
            UnhandledException += Application_UnhandledException;

            // Standard XAML initialization
            InitializeComponent();

            // Phone-specific initialization
            InitializePhoneApplication();

            // Language display initialization
            InitializeLanguage();

            AppSettings = new AppSettings();

            // Show graphics profiling information while debugging.
            if (Debugger.IsAttached)
            {
                // Display the current frame rate counters.
                Application.Current.Host.Settings.EnableFrameRateCounter = false;

                // Show the areas of the app that are being redrawn in each frame.
                //Application.Current.Host.Settings.EnableRedrawRegions = true;

                // Enable non-production analysis visualization mode,
                // which shows areas of a page that are handed off GPU with a colored overlay.
                //Application.Current.Host.Settings.EnableCacheVisualization = true;

                // Prevent the screen from turning off while under the debugger by disabling
                // the application's idle detection.
                // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
                // and consume battery power when the user is not using the phone.
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }

            InitDatabase();
        }

        public static SQLiteConnection DbConnection { get; set; }
        public static string DbPath = Path.Combine(Path.Combine(ApplicationData.Current.LocalFolder.Path, "db.sqlite"));

        public void InitDatabase()
        {
            // establish connection
            DbConnection = new SQLiteConnection(DbPath);
               
        }

Das File (db.sqlite) wird beim erstmaligen Aufruf automatisch erzeugt. Damit haben wir nun eine leere Datenbank erstellt.
Nun gehts an das Erzeugen von Tabellen.

Tabellen erstellen
Tabellen werden an Hand von Klassen erzeugt. Die Eigenschaften der Klasse werden dann mit Attributen versehen, welche z.B. Angaben über AutoIncrement oder Primärschlüssel machen oder SQlite mitteilen, dass eine Eigenschaft ignoriert werden soll (z.B. für logische Properties).

public class Profile : INotifyPropertyChanged
    {
        private int _id = -1;
        /// <summary>
        /// You can create an integer primary key and let the SQLite control it.
        /// </summary>
        [PrimaryKey, AutoIncrement]
        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (value != _id)
                {
                    _id = value;
                    NotifyPropertyChanged("ID");
                }
            }
        }

        private string _userName;
        /// <summary>
        /// Sample VacationViewModel property; this property is used in the view to display its value using a Binding.
        /// </summary>
        /// <returns></returns>
        public string UserName
        {
            get
            {
                return _userName;
            }
            set
            {
                if (value != _userName)
                {
                    _userName = value;
                    NotifyPropertyChanged("UserName");
                }
            }
        }

/// <summary>
        /// Gets the color of the state.
        /// </summary>
        /// <value>
        /// The color of the state.
        /// </value>
        [SQLite.Ignore]
        public System.Windows.Media.Brush StateColor
        {
            get
            {
                switch (this.State)
                {
                    case "genehmigt":
                        return new SolidColorBrush(Colors.Green);

                    case "abgelehnt":
                        return new SolidColorBrush(Colors.Red);

                    default:
                        return new SolidColorBrush(Colors.Yellow);
                }
            }
            set
            {
                // ignore
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
}

Wie Ihr seht, leite ich von INotifyPropertyChanged ab. Das hat nichts mit SQLite zu tun, sondern mit MVVM, man kann die Klasse also gleich direkt weiterverwenden und muss kein eigenes ViewModel erzeugen… Aber das ist jetzt nicht Teil des Blogeintrags. Interessanter sind die Attribute PrimaryKey, AutoIncrement und SQLite.Ignore, welche selbsterklärend sind.

Hat man diese Klasse fertig, kann man eine Tabelle erzeugen lassen.

            // establish connection
            DbConnection = new SQLiteConnection(DbPath);

            //DbConnection.DropTable<Vacation>();
            // create table if not exists
            DbConnection.CreateTable<Vacation>()

Datensätze hinzufügen

Nun kann man ganz einfach Datensätze erzeugen. Demonstrieren möchte ich euch das am Beispiel von Dummy-Daten, welche man z.B. zum Testen und erstmaligen Launch einer App hinzufügen kann:


public void InitDatabase()
        {
            // establish connection
            DbConnection = new SQLiteConnection(DbPath);

            // create table if not exists
            //DbConnection.DropTable<Profile>();
            DbConnection.CreateTable<Profile>();

            for (int i = 0; i <= 50; i;)
            {
                var profile = new Profile();
                profile .UserName = @"username";
                DbConnection.Insert(profile );
            }
        }

Cheers,
Christian

WP8 – Einbinden von SQLite – Projekt aufsetzen

Hallo Leute,

heute möchte ich euch zeigen, wie Ihr SQLite in WP8 verwenden könnt. Vielen Dank an Nokia für den hervorragenden WIKI-Eintrag: .

Als ersten Schritt ist es notwendig die Extension „SQLite for Windows Phone“ zu installieren. Das Geht über TOOLS -> Extensions and Updates -> online -> Suche nach „sqlite“. Dann solltet Ihr folgendes Bild bekommen:

Extensions-and-update-window-1.png

Dieses Paket muss installiert werden, am Ende sollte folgendes Bild rauskommen:

 

Extensions-and-update-window-2.png
Zusätzlich benötigt es „leider“ eine C++ – Bridge zwischen dem SQLite SDK und sqlite-net. Am einfachsten lädt man sich dieses Projekt von herunter.
Dieses Projekt muss man nun seiner Visual Studio Solution hinzufügen und eine Referenz in das eigene WP8-Projekt hinzufügen. Alternativ kann man natürlich das GIT-Projekt einfach kompilieren und lediglich die DLL referenzieren.

Als letzten Schritt muss nur noch via NuGet das sqlite-net Package eingebunden werden. Dazu klickt einfach euer WP8-Projekt im Solution Fenster mit der rechten Maustaste an und klickt auf „Manage NuGet Packages“.

Adding-sqlite-for-wp8-support.png

 

Es gibt nun zwei Probleme, welche potentiell auftreten können. In meinem ersten Gehversuch sind beide aufgetreten, hier die Lösung:

1.) „The type or namespace ‚Community‘ could not be found.
Das ist relativ simple zu lösen, indem man einfach ein Build-Symbol hinzufügt: USE_WP8_NATIVE_SQLITE

2013-11-21 15_58_44-at.wienit.vacation.solution (Running) - Microsoft Visual Studio (Administrator)

2.) „Any CPU“ problem

Warning-message-any-cpu.png

Auch das geht recht einfach, man muss, wenn man den Emulator verwendet x86 umstellen (Solution -> Click on Configuration Properties -> Configuration Manager), wenn man am Device testen möchte auf ARM.

Cheers,
Christian