Tip of the day – LoopingSelector

Ihr kennt wahrscheinlich alle den TimePicker bzw. DateTimePicker, welche diese sehr schön umgesetzte Auswahl der Uhrzeit bzw. des Datums haben.
So eine Auswahl wollte ich auch für eine meiner Apps haben (Zune Timer) und die Lösung dazu ist der LoopingSelector.
Das müsst ihr machen:
Zuerst müsst ihr bei den Referenzen das Phone Toolkit hinzufügen (Wenn ihr dies noch nicht installiert habt, dann mal schnell nachholen. Sind ein paar sehr gute neue Controls dabei 😉 )

Dort wählt ihr:

Dann braucht ihr noch diesen Codeausschnitt auf eurer Seite wo ihr den LoopingSelector verwenden wollt:

xmlns:primitives="clr-namespace:Microsoft.Phone.Controls.Primitives;assembly=Microsoft.Phone.Controls.Toolkit"

Jetzt könnt ihr einen LoopingSelector erzeugen, mit dem folgenden Code:

<primitives:LoopingSelector
                x:Name="TutorialLoopingselector"
                Width="100"
                ItemSize="100,100"
                Height="550"
                ItemMargin="6"
                HorizontalAlignment="Center"                >
                <primitives:LoopingSelector.ItemTemplate>
                    <DataTemplate>
                        <StackPanel
                            HorizontalAlignment="Left"
                            VerticalAlignment="Bottom"
                            Margin="6">
                            <TextBlock
                                Text="{Binding}"
                                FontSize="40"
                                FontFamily="{StaticResource PhoneFontFamilySemiBold}"
                                Margin="0,-8"/>
                        </StackPanel>
                    </DataTemplate>
                </primitives:LoopingSelector.ItemTemplate>
            </primitives:LoopingSelector>

Hier könnt ihr natürlich auch alles Individuell verändern, zu dem, was ihr gerade braucht.
Das war es auch schon fast. Es fehlt nur noch die Implementation der Datasource.
Die Datasource besteht im Grunde nur aus ein paar kleinen Funktionen. Was sie hat, ist eine Funktion um den nächsten Wert zu bekommen, sowie eine Funktion um den vorherigen Wert zu bekommen. Dann braucht sie natürlich auch noch den aktuell angewählten Wert.

Um diese Klasse dann auch wirklich als Datasource benutzen zu können, muss sie von ILoopingSelectorDataSource
Erben.
Dafür muss vorher noch:

using Microsoft.Phone.Controls.Primitives;

hinzugefügt werden.
Hier die komplette Klasse. Ich habe diese für Klasse für einen Intselector gemacht (Bsp. wäre für einen Sekundenselector). Aber man kann natürlich seine komplett eigenen Schreiben. Man könnte ja auch ein Array übergeben an die Datasource, welches irgendwelche Daten enthält und dieses damit auswählen lassen. (Wie die Darstellung davon ist, kann dann natürlich im DataTemplate festgelegt werden)
Wie ihr seht, gibt es viele Möglichkeiten für eine Datasource. Hier die wahrscheinlich am häufigsten genutzte für einen Intselector:

public class IntDatasource : ILoopingSelectorDataSource
    {
        private int _selectedItem;
        private int minValue;
        private int maxValue;
        private int increment;
        public IntDatasource()
        {
            this.MaxValue = 10;
            this.MinValue = 0;
            this.Increment = 1;
            this.SelectedItem = 0;
        }

        public int MinValue
        {
            get
            {
                return this.minValue;
            }
            set
            {
                if (value >= this.MaxValue)
                {
                    throw new ArgumentOutOfRangeException("MinValue", "MinValue cannot be equal or greater than MaxValue");
                }
                this.minValue = value;
            }
        }

        public int MaxValue
        {
            get
            {
                return this.maxValue;
            }
            set
            {
                if (value <= this.MinValue)
                {
                    throw new ArgumentOutOfRangeException("MaxValue", "MaxValue cannot be equal or lower than MinValue");
                }
                this.maxValue = value;
            }
        }

        public int Increment
        {
            get
            {
                return this.increment;
            }
            set
            {
                if (value < 1)                 {                     throw new ArgumentOutOfRangeException("Increment", "Increment cannot be less than or equal to zero");                 }                 this.increment = value;             }         }         public object GetNext(object relativeTo)         {             int nextValue = (int)relativeTo + this.Increment;             if (nextValue > this.MaxValue)
            {
                nextValue = this.MinValue;
            }
            return nextValue;
        }

        public object GetPrevious(object relativeTo)
        {
            int prevValue = (int)relativeTo - this.Increment;
            if (prevValue < this.MinValue)
            {
                prevValue = this.MaxValue;
            }
            return prevValue;
        }

        public object SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if ((int)value != _selectedItem)
                {
                    int valueWrapper = (int)value;
                    if ((valueWrapper != _selectedItem))
                    {
                        object previousSelectedItem = _selectedItem;
                        _selectedItem = valueWrapper;
                        EventHandler handler = SelectionChanged;
                        if (null != handler)
                        {
                            handler(this, new SelectionChangedEventArgs(new object[] { previousSelectedItem }, new object[] { _selectedItem }));
                        }
                    }
                }
            }
        }

        public event EventHandler SelectionChanged;
    }

Was müsst ihr sonst noch machen. Naja, nicht viel. Jetzt fehlt nur noch die Zuweisung der Datasource zu eurem Loopingselector, typischerweise im Konstruktor der Seite auf der der Loopingselector platziert ist:

public MainPage()
        {
            InitializeComponent();
            TutorialLoopingselector.DataSource = new IntDatasource() { Increment = 2, MaxValue = 60, MinValue = 0, SelectedItem = 30 };
        }

Ich arbeite an einer Möglichkeit euch den Quelltext zur Verfügung zu stellen. Leider bittet wordpress nicht die Möglichkeit Zip Dateien anzuhängen. Ich schaue mal, ob ich eine andere Lösung finden kann.

Ich hoffe ich konnte euch hiermit einen kleinen Einblick in Loopingselectoren geben.
Hier gibt es auch noch mehr Infos:

geekchamp

Ihr habt fragen, Anregungen oder sonstige Meinungen. Immer nur her damit in den Kommentaren 😉

Advertisements

6 Gedanken zu „Tip of the day – LoopingSelector

  1. Pingback: Anonymous

  2. ErdnussFlipS

    Also ich hab das jetzt mal so probiert, und bei mir meckert er folgendes an:
    „Trainerhilfe.ViewModels.IntDatasource“ implementiert den Schnittstellenmember „Microsoft.Phone.Controls.Primitives.ILoopingSelectorDataSource.SelectionChanged“ nicht. „Trainerhilfe.ViewModels.IntDatasource.SelectionChanged“ hat nicht den entsprechenden Rückgabetyp „System.EventHandler“ und kann „Microsoft.Phone.Controls.Primitives.ILoopingSelectorDataSource.SelectionChanged“ daher nicht implementieren.

    Ich hab aber „using Microsoft.Phone.Controls.Primitives;“ und „public event EventHandler SelectionChanged;“ drinne.
    Steh ich grad aufm Schlauch?

    Antwort
    1. dehodev Autor

      Also wenn du den Code so übernommen hast, sollte es funktionieren, gerade nochmal erfolgreich neu kompiliert.
      Stelle sicher das du:
      public event EventHandler SelectionChanged;
      verwendest.

      public event EventHandler<System.Windows.Controls.SelectionChangedEventArgs> SelectionChanged;
      Führt bei mir zu einem ähnlichen Fehler.
      Sollte das das Problem nicht beheben, schick mir kurz den Code, dann kann ich mir das genauer ansehen.

      Antwort
  3. Blaubarschboy

    leider kommt bei mir das selbe wie bei ErdnussFlipS.
    „Fehler 1 ‚Zahlenumrechner.IntDatasource‘ implementiert den Schnittstellenmember ‚Microsoft.Phone.Controls.Primitives.ILoopingSelectorDataSource.SelectionChanged‘ nicht. ‚Zahlenumrechner.IntDatasource.SelectionChanged‘ hat nicht den entsprechenden Rückgabetyp ‚System.EventHandler‘ und kann ‚Microsoft.Phone.Controls.Primitives.ILoopingSelectorDataSource.SelectionChanged‘ daher nicht implementieren. X:\XX\XXXX\XXXX\WindowsPhone\Zahlenumrechner\Zahlenumrechner\MainPage.xaml.cs 53 18 Zahlenumrechner“

    Hast du einen Tipp? Ich war schon so froh, endlich mal eine vernünftige Anleitung zum LoopingSelector zu finden! Und Danke dafür! Das ist nämlich einfach ein super Steuerelement in einer WP GUI. Ich hoffe du kannst mir helfen – da der Fehler hier ja schonmal vor kam. Leider funktioniert auch der Link zu Geekchamps nicht (bzw. funktionieren tut er schon, allerdings gibt’s wohl den Artikel bei denen nicht mehr).

    Antwort
    1. dehodev Autor

      Ein Tipp um dies ganz einfach selbst zu lösen:
      mit dem Cursor auf das Interface von der Klasse, Tastenkombi „Strg“ + „.“, „Implement Interface“ aussuchen und der löst das Problem automatisch für dich.

      edit: woah, jetzt sehe ich warum mein Kommentar oben keinen Sinn ergeben hat, geht verloren wegen html tags…..

      public event EventHandler<System.Windows.Controls.SelectionChangedEventArgs> SelectionChanged;

      Antwort

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s