none
Ändern eines TextBlocks von einer anderen Seite RRS feed

  • Frage

  • Hallo zusammen,

    ich versuche in einer UWP-App von einer anderen Seite aus mit einem Button einen TextBlock auf der MainPage zu ändern.

    Da ich nicht rausgefunden habe, wie ich beim Buttonklick direkt die Text-Eigenschaft des TextBlocks ändern kann, habe ich auf der MainPage eine Methode erstellt, die das mit dem entsprechenden Inputparameter tut.

    Code für die zweite Seite: hier wird eine Methode auf der MainPage aufgerufen und der Text als string übergeben.

        public partial class Page2: Page
        {
            public MainPage MainPage = new MainPage();
            public PropertiesControl()
            {
                this.InitializeComponent();
            }
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                MainPage.testtest("Irgendein Text");
            }
        }

    Das hier wäre dann die Methode auf der MainPage, die den Text des TextBlocks ändert:

            public void testtest(string text)
            {
                TestTextBlock.Text = text;
            }

    Der Code wird durchlaufen, für den Inhalt von TestTextBlock.Text wird im Debugger auch "Irgendein Text" angezeigt, der sichtbare Text des TextBlocks ändert sich jedoch nicht.

    Wenn ich auf der MainPage einen Button erstelle, der genau die selbe Methode aufruft, funktioniert es. Der sichtbare Text "Hier geht es" wird angezeigt:

            public void testtest(string text)
            {
                TestTextBlock.Text = text;
            }
            public void Button_Click(object sender, RoutedEventArgs e)
            {
                testtest("Hier geht es");
            }

    Weiß jemand Rat?

    Vielen Dank im Voraus, Gruß René

    Freitag, 14. April 2017 15:14

Antworten

  • Hallo René,

    in der App.cs würde ich da nicht machen. Ich würde ein ViewModel anlegen. Dieses dann entweder über ein Singelton oder ein statisches Property zur Verfügung stellen. Auf diese so erzeugte Klasse kann dann jedes UserControl und jede weiter Page zugreifen. 

    Ich habe mal nach deinem Beispiel oben ein App mit ViewModel erstellt. Um es zu testen, muss Du noch ein mp3 Lied in den Assets Ordner packen und es Track01.mp3 nennen. Das Projekt findest Du auf GitHub 


    Gruß Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP

    Cross Platform Canvas for UWP, Android, iOS

    UWP Community Toolkit Sample App

    Alle Größenangaben in UWP müssen durch 4 teilbar sein

    • Als Antwort markiert _Queequack_ Samstag, 30. Dezember 2017 12:46
    Freitag, 24. November 2017 14:49
  • Hallo,

    wie bereits schon oben steht solltest du nicht eine neue Instanz von Mainpage erzeugen. Was du machen könntest:

    In deiner Mainpage eine statische Referenz anlegen:

        public sealed partial class MainPage : Page
        {
            public static MainPage CurrentMainpage;
    
            public MainPage()
            {
                this.InitializeComponent();
                CurrentMainpage = this;
            }
        }

    Diese statische Referenz kannst du dann in der Page2 benutzen, um deine Funktion aufzurufen:

        public sealed partial class Page2 : Page
        {
            private MainPage currentMainpage;
    
            public Page2()
            {
                this.InitializeComponent();
                currentMainpage = MainPage.CurrentMainpage;
            }
        }

    Alternativ dazu:

    Du könntest in der Page2 ein Event auslösen, welche du in der Mainpage abonnierst... Wenn also Page2 etwas ändert bekommt Mainpage das umgehend mit und ändert die entsprechenden Werte...

    Nur so als Idee

    jc-design


    JC-DESIGN

    • Als Antwort markiert _Queequack_ Freitag, 21. April 2017 12:38
    Freitag, 14. April 2017 21:44

Alle Antworten

  • Hallo René,

    das wir so nicht gehen, auch solltest Du das so nicht weiter versuchen. Durch new MainPage() erzeugst Du nur eine neue Instanz von MainPage, diese hat aber mit der vorherigen Page nichts zutun.  

    Um dir das einfach zu verdeutlichen was Du grade machst ein kleines Beispiel:

    Sagen wir mal Du hast dir ein neues Auto (Auto1) gekauft von der Marke XY. Da dir das Auto sehr gut gefallen hat kaufst Du dir nochmal das selbe Auto (Auto2). Jetzt fährst Du mit Auto2 300 km. Der Tachostand hat sich nur im Auto2 geändert. Du versucht aber den Tachostand des Auto1 durch fahren des Auto2 zu änder, was nicht gehen kann. Du brauchst also die 1 Instanz von MainPage. Ich würde dir aber nicht empfehlen die 1 Instanz von MainPage in deiner anderen Klasse (Page2) zu ändern. Arbeite lieber mit Übergabeparametern wie unten im beispiel

    Schau dir mal das beispiel von Microsoft zur Peer-zu-Peer Navigation an.

    Weiter unten ist auch gezeigt wie Du Daten übergibst "Übergeben von Informationen zwischen Seiten"


    Gruß, Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP


    Freitag, 14. April 2017 17:13
  • Hallo Thomas,

    vielen Dank für die Antwort und die Erklärung :) Die Methodik und das Übergeben von Parametern zwischen Seiten ist mir bekannt. Ich denke ich muss mein Problem weiter detaillieren. Dazu noch ein kleines Beispiel. Ich habe eine Methode auf der MainPage. Diese rufe ich (ja ok, es ist über eine Instanz) über Page2 auf. Was ich nicht verstehe ist, dass die Methode auf der MainPage durchlaufen wird und alle Parameter etc. entsprechend geändert werden, nur der Text des TextBlocks nicht. D.h. die Methode auf der MainPage wird aufgerufen (diesmal ohne Parameterübergabe).

    // Auf Page2
    ...
            public MainPage MainPage = new MainPage();
    ...
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                MainPage.testtest();
            }
    
    // Auf der MainPage
            public void testtest()
            {
                TestTextBlock.Text = "Hier steht Text";
            }

    Warum möchte ich das ermöglichen:

    Ich habe eine MainPage, die immer sichtbar und aktiv bleibt. Diese hat ein SpliView-Element (ohne SplitView.Content). In der SplitView.Pane gibt es eine Art Menü, gebildet durch ListBoxes (so wie in der Hamburger-Navigation). Der verdeckte Teil der SplitView.Pane enthält einen Frame. Dieser Frame wird gefüttert mit verschiedenen Xaml-Seiten, je nach Auswahl. D.h. die "eingebettete Page2" wird in der SpliView.Pane (begrenzte Breite) geöffnet, während die MainPage im Hintergrund weiterhin sichtbar bleibt. Die Auwswahl verschiedener "Menüs" ist notwendig.

    Ziel ist es nun, wenn ich einen Schalter, wie z.B. "Ton aus" in dieser Page2 anklicke, dass auf der MainPage in bspw. einem MediaElement der Ton ausgeschaltet wird. Ist das SplitView.Panel vielleicht die falsche Wahl?

    Hier eine kleine Grafik um die (vermeintlich) simple Logik zu zeigen. Scheint doch mehr dahinter zu stecken :)

    Gruß René

    Freitag, 14. April 2017 20:26
  • Wenn Du auf Page 2 wirklich eine neue MainPage erzeugst mit "public MainPage MainPage = new MainPage();"

    kannst sich nichts auf der aktiven MainPage ändern.

    Was gehen würde ist das:

    var frame = Window.Current.Content as Frame;
                var mp = (MainPage)frame.Content;

    Du magst deine gründe dafür haben, aber auf dauer wird das nichts. Warum nutzt Du dafür keine UserControls? Diese könntest Du in den SplitView.Content einfach nach bedarf laden. 

    Deine Idee geht in Richtung MVVM. Schau dir mal das Beispiel an


    Gruß, Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP


    Freitag, 14. April 2017 21:10
  • Hallo,

    wie bereits schon oben steht solltest du nicht eine neue Instanz von Mainpage erzeugen. Was du machen könntest:

    In deiner Mainpage eine statische Referenz anlegen:

        public sealed partial class MainPage : Page
        {
            public static MainPage CurrentMainpage;
    
            public MainPage()
            {
                this.InitializeComponent();
                CurrentMainpage = this;
            }
        }

    Diese statische Referenz kannst du dann in der Page2 benutzen, um deine Funktion aufzurufen:

        public sealed partial class Page2 : Page
        {
            private MainPage currentMainpage;
    
            public Page2()
            {
                this.InitializeComponent();
                currentMainpage = MainPage.CurrentMainpage;
            }
        }

    Alternativ dazu:

    Du könntest in der Page2 ein Event auslösen, welche du in der Mainpage abonnierst... Wenn also Page2 etwas ändert bekommt Mainpage das umgehend mit und ändert die entsprechenden Werte...

    Nur so als Idee

    jc-design


    JC-DESIGN

    • Als Antwort markiert _Queequack_ Freitag, 21. April 2017 12:38
    Freitag, 14. April 2017 21:44
  • Hallo,

    vielen Dank für die Antworten. Derzeit blende ich aufgrund der geringen Komplexität der App einfach ein GridView ein oder aus.

    Die Lösung von jc-design hilft auf einfache Art von Seite 2 aus eine Funktion auf Seite 1 zu starten.

    Gruß René

    Freitag, 21. April 2017 12:38
  • Hi Thomas,

    ich habe mir MVVM und UserControl mal angeschaut. Zuerst dachte ich, UserControls könnten zielführend sein. Ganz simpel: Zwei UserControl-XAMLs aufbauen und auf der MainPage eins davon anzeigen. Beim Klick auf einen Button kann einfach ein anderes UserControl-XAML geladen werden. Ok soweit.

    Mein Problem dabei ist aber wieder das gleiche. Ich möchte innerhalb des UserControls Funktionalität auf der MainPage ansprechen (als Beispiel: Mit dem Butten im UserControl einen TextBlock auf der MainPage ändern). Ich stehe also wieder vor dem identischen Problem, wie mit den zwei Seiten. Nochmal kurz zum Hintergrund: Die UserControls sollen so etwas wie Menüs darstellen. Z.B. ein Menü für die Lautstärke (eines MediaElements auf der MainPage), ein Menü für die Hintergrundfarbe (eines Grids auf der MainPage), etc (sind nur Beispiele!).

    Oder mache ich was falsch?

    Gruß René

    Montag, 22. Mai 2017 20:35
  • Hallo René,

    Du kannst doch bei erzeugen deines UserControl die Controls mitgeben die Du brauchst. So in der Art:

    public MyUserControl1(TextBlock tbtext)
            {
                this.InitializeComponent();
    
                tbtext.Text = "la";
            }
    
    public MainPage()
            {
                this.InitializeComponent();
    
                 ucWrapper.Children.Add(new UC.MyUserControl1(tbText));
            }


    <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
    
                <StackPanel>
                    <TextBlock Text="Text" x:Name="tbText" />
                </StackPanel>
                
                <Grid Grid.Row="1" x:Name="ucWrapper">
                    
                </Grid>
                
            </Grid>


    Besser ist es natürlich mit Models zu arbeiten. Aber für deine ersten versuche in UWP finde ich das Ok.

    Eine weiter Möglichkeit wären noch ContentDialoge (Popups). Der Vorteil daran ist das Du asynchron auf das Ergebnis warten kannst und Du dir viel Platz sparst was auf kleinen Displays von vorteil sein kann


    Gruß, Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP





    Montag, 22. Mai 2017 21:28
  • Hallo Thomas,

    ich bin nun dabei meine App(s) etwas aufzumotzen und sauberer zu programmieren. Um dieses Thema wieder aufzugreifen, habe ich bezüglich der Navigation für meine Zwecke den Rahmen einer App aufgebaut (siehe Screenshot). Es geht rein um Databinding und die grundsätzliche Navigation. Später wird es natürlich mit SplitView etc. viel schöner aussehen.

    Das ganze ist an MVVM angelehnt. Die Daten werden, wenn vorhanden, zunächst aus einer Settings-Datei (json Format, anderes Thema) eingelesen. Durch das Binding werden die Elemente entsprechend angepasst (TexBlock funtktioniert ohne weiteres, ToggleSwitch geht ebenfalls, das Binding für den Initialwert der Combobox ist mir noch nicht gelungen - dazu mache ich vielleicht einen anderen Thread auf). Sobald eine Eigenschaft geändert wird, wird dies auch direkt in der Settings-Datei wieder gespeichert. Dieses Beispiel ist reichlich ungeeignet, da beim Schalten eines ToggleSwitches durch das Binding alle ToggleSwichtes geschaltet werden. Dadurch wiederum wird das Speichern mehrfach ausgelöst, was zur Überschneidung der Prozesse und damit zur Exception führt (da die Datei beim Speicherversuch schon geöffnet ist). Den Binding Mode auf "OneTime" zu stellen ergibt wahrscheinlich Sinn, da das ja nur einmal beim Starten befüllt werden muss. Stati in Form von Farben, Texten (also keine Eingabeelemente) darzustellen ergibt evtl. mehr Sinn.

    Zur Navigation: Es wird mehrere solcher Fenster (wie das blaue und das grüne) geben, jedes wird unterschiedlich aussehen und verschiedene Optionen beinhalten. Stellen wir uns einfach Einstellungsmenüs für Audio, Wecker, Raumsteuerung... irgendwas vor. 

    Ich habe spontan keine Möglichkeit gefunden zu einem UserControl (hier grün dargestellt) zu navigieren. Daher baue ich es in diesem Beispiel einfach direkt ein (weitere UserControls würden im Grid o.ä. einfach übereinander liegen). So sind alle UserControls und ihre Inhalte initialisiert, wenn die MainPage initialisiert ist. Wäre es denn "richtiger" eine Page im Frame zu verwenden (hier blau dargestellt)? diese wird erst initialisiert, sobald zu ihr navigiert wird. Ich vermute, das ist Ressourcensparender?

    Was mir sehr geholfen hat, war unter Anderem Bob Tabor: LINK (Video: Part 26 - Exercise: The Daily Rituals App)

    Gruß René

    Donnerstag, 2. November 2017 15:18
  • Hallo René,

    das mit dem speicher löse ich meist über ein Stack und einem Timer. Da ich aber davon ausgehe das Du nur ein Model hast das Du als Json speicherst!? Hier eine etwas abgewandelte Möglichkeit

    static DispatcherTimer dispatcherTimer;
    static int UpdateSteps = 0;
    static int maxUpdateSteps = 2;
    static bool timerActive = false;
    static bool isInitTimer = false;
    
    static void InitTimer()
    {
        dispatcherTimer = new DispatcherTimer
        {
            Interval = new TimeSpan(0, 1, 0)
        };
        isInitTimer = true;
    }
    
    //Jeder Änderung in der View, ruft diese Methode auf 
    public static void SaveModelToJson()
    {
        if (timerActive == false)
        {
            timerActive = true;
            dispatcherTimer.Tick += DispatcherTimer_Tick;
            dispatcherTimer.Start();
        }
    
        UpdateSteps = 0;
    }
    
    public static void StopTimer()
    {
        if (dispatcherTimer != null)
        {
            dispatcherTimer.Stop();
            dispatcherTimer.Tick -= DispatcherTimer_Tick;
            timerActive = false;
        }
    }
    
    static bool updateDBBusy = false;
    private static void DispatcherTimer_Tick(object sender, object e)
    {
        if (updateDBBusy)
        {
            return;
        }
        else
        {
            Task.Run(() => UpdateJson());
    
            if (UpdateSteps == maxUpdateSteps)
            {
                dispatcherTimer.Stop();
            }
        }
    }
    
    static async void UpdateJson()
    {
        updateDBBusy = true;
    
        //erst hier wird das Model gespeichert und zwar in einem weiteren Thread
    
        UpdateSteps++;
        updateDBBusy = false;
    }

    Damit speichert immer nur ein Prozess. Zu Konflikten sollte es nicht kommen. Die UpdateSteps nutze ich gern da ich davon ausgehen das der User gleich mehrere Einstellungen verändert. Man kann natürlich den Timer auch dauerhaft laufen lassen, finde ich persönlich aber nicht so gut.

    Die Navigation von UWP ist Geschmackssache. Ich nutze sie ungern da mir schon allein die Animation nicht zusagt. Das ein und ausblenden von UserControls ist gängige Praxis. Verbraucht aber ein UC viele Ressourcen und wird kaum genutzt, sollte man sich etwas anderes überlegen.

    Bei UWP ist es aber so das UC die bei initialisieren auf Visibility.Collapsed stehen, nicht gerendert werden und auch nicht mit Elementen gefüllt werde. Damit verbrauchen sie auch kaum Ressourcen. Bei großen UC kann das beim ersten einblenden zu ruckle oder kurzen Blockaden führen.

    In der Programmierung versucht man meistens Element nur einem zu erstellen und nicht jedes mal neu zu laden. CPU-Zeit ist mir wichtiger als RAM Verbraucht. Der RAM Verbrauch sollte sich aber in grenzen halten.


    Gruß Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP

    Cross Platform Canvas for UWP, Android, iOS

    UWP Community Toolkit Sample App

    Alle Größenangaben in UWP müssen durch 4 teilbar sein

    Donnerstag, 2. November 2017 17:43
  • Hallo René,

    hier mal ein paar Tipps von mir:

    "... Dieses Beispiel ist reichlich ungeeignet, da beim Schalten eines ToggleSwitches durch das Binding alle ToggleSwichtes geschaltet werden. ..." => Du kannst ja vorher prüfen, wie der Zustand ist bevor du eine Aktiv ausführst

    "... Ich habe spontan keine Möglichkeit gefunden zu einem UserControl (hier grün dargestellt) zu navigieren. ..." => Du kannst nur auf Pages Navigieren... dort kannst du natürlich ein einzigen UserControl anzeigen

    "... Dadurch wiederum wird das Speichern mehrfach ausgelöst, was zur Überschneidung der Prozesse und damit zur Exception führt (da die Datei beim Speicherversuch schon geöffnet ist) ..." => Die Idee von Markus finde ich sehr gut. Du könntest natürlich auch jede Einstellung in einer eigenen Datei abspeichern

    "... Initialwert der Combobox ist mir noch nicht gelungen ..." => Du kannst versuchen ein Bindung zu "SelectedItem" zu realisieren. Mittles x:Bind habe ich es bisher nicht geschafft. Ich nutze das Loaded-Event, um den Startwert zu setzen

    Grüße

    jc-design


    JC-DESIGN

    Freitag, 3. November 2017 18:16
  • Man kann auch über x:Bing SelectedItem setzen. Zu beachten ist nur das für TwoWay ein Converter benötigt wird

    Das ViewModel:

    public class BingLanguageViewModel : INotifyPropertyChanged
    {
        BingLanguageItemViewModel _selectedItem = new BingLanguageItemViewModel();
        public BingLanguageItemViewModel SelectedItem { get { return _selectedItem; } set { _selectedItem = value; } }
        public ObservableCollection<BingLanguageItemViewModel> Languages { get; set; }
    
        public BingLanguageViewModel()
        {
            Languages = new ObservableCollection<BingLanguageItemViewModel>();
    
            foreach (var item in Models.BingTrans.ListLanguage)
            {
                var l = new BingLanguageItemViewModel() { Code = item.Key, Name = TWyTec.StoreLanguages.GetNameFromCode(item.Key) };
    
                if (item.Key == TWyTec.StoreLanguages.GetUserLanguageCode.ToLower())
                    SelectedItem = l;
    
                Languages.Add(l);
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            // Raise the PropertyChanged event, passing the name of the property whose value has changed.
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    public class BingLanguageItemViewModel
    {
        public string Name { get; set; }
        public string Code { get; set; }
    }
    
    public class BingModelConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return value;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return value;
        }
    }
    <ComboBox Margin="10,18,10,0" Header="Bing language" HorizontalAlignment="Stretch" 
                      ItemsSource="{x:Bind BingLanguageViewModel.Languages}" 
                      SelectedItem="{x:Bind BingLanguageViewModel.SelectedItem, Mode=TwoWay, Converter={StaticResource BingModelConverter}}" Grid.Row="2">
                <ComboBox.ItemTemplate>
                    <DataTemplate x:DataType="viewModel:BingLanguageItemViewModel">
                        <TextBlock Text="{x:Bind Name}" />
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>



    Gruß Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP

    Cross Platform Canvas for UWP, Android, iOS

    UWP Community Toolkit Sample App

    Alle Größenangaben in UWP müssen durch 4 teilbar sein

    Samstag, 4. November 2017 00:55
  • Hallo Thomas,

    verstehe ich das richtig:  Angenommen der User ändert 2 (oder auch mehr) Parameter (fast) zeitgleich.

    Beim ersten Mal wird der Timer_Tick aufgerufen. Da der Timer 1 Minute ist, wird bei jeder weiteren Änderung UpdateSteps auf 0 gesetzt.

    updateDBBusy == true in Timer_Tick dürfte doch niemals eintreten, es sei denn das Updaten dauert läger als der Timerinterval (1 Minute), oder?

    Weiterhin bedeutet das, dass jede Änderung des Users nach der ersten, die er innerhalb des Timerintervalls getätigt hat erst gespeichert wird, wenn der Timer das nächste Mal "tickt", als nach einer Minute.

    Noch eine Frage: StopTimer() wird nicht aufgerufen. Wolltest du das evtl. im Timer_Tick Event tun, wenn maxUpdateSteps erreicht wird (anstelle von dispatcherTimer.Stop();?

    Was UserControl und Page betrifft bin ich immer noch unsicher. Es wird am Ende wohl auf die Komplexität der App ankommen. Das wird sich noch ergeben... Andererseits ist es nicht sehr aufwändig den Code von Page zu UserControl oder umgekehrt zu ändern. Ich habe da noch eine Frage: Ich habe den Moment verpasst, indem das passiert ist... Aber ich bekomme an folgender Stelle plötzlich einen Fehler:

    public sealed partial class MainPage : Page

    Daher kommentiere ich //: Page einfach aus, dann läuft alles wie gewohnt.

    Gruß René

    [EDIT]:

    Ja, ich speichere Json :) Allerdings ohne NuGet Paket, sondern so (das laden quasi analog dazu... Und filename vorher als string deklariert):

    private async Task saveWeckerDataAsync()
       {
       var jsonSerializer = new DataContractJsonSerializer(typeof(WeckerParameter));
       using (var stream = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(fileName, CreationCollisionOption.ReplaceExisting))
       {
          jsonSerializer.WriteObject(stream, _WeckerParameter);
       }
    }


    • Bearbeitet _Queequack_ Samstag, 4. November 2017 08:18
    Samstag, 4. November 2017 08:13
  • Hallo Thomas,

    mit dem Converter habe ich schon rumgespielt, kam aber noch nicht zum Ergebnis. Muss ich noch weiter probieren...

    Ich gehe davon aus, dass der Converter auch für OneTime notwendig ist? Denn nur beim Initialisieren soll die Seite übernehmen, was hinter den gespeicherten Parametern steckt. Anschließend werden die Parameter ja nur noch gesetzt und abgespeichert.

    Wie mache ich das eigentlich bei einem einfachen TextBlock mit x:Bind? mit <TextBlock Text="{Binding WeckerStatus}"/> brauche ich nichts weiter festzulegen. mit <TextBlock Text="{x:Bind WeckerStatus}"/> findet er die "WeckerStatus"-Eigenschaft nicht und klagt über einen invalid path "WeckerStatus". Ich habe nicht herausgefunden, wie ich ein ItemTemplate oder DataTemplate o.ä. wie bei deiner Combobox oben, einfügen kann.

    Gruß René

    Samstag, 4. November 2017 08:33
  • Genau. Solange der User Einstellungen vornimmt, bleibt der Timer aktive. Stimmt dispatcherTimer.Stop() ist durch StopTimer zu ersetzen. Habe das übersehen. In deinem Fall und dem "langen" Timerinterval sollte updateDBBusy == true eigentlich nie auftreten. Aber vielleicht willst Du mit dem interval auch später etwas rumspielen. So ist der Schutz weiterhin gewährleistet.

    Experimentiere mit UC, Page und Navigate etwas rum. Keins meiner Programme war am ende so strukturiert wie ich es mir am Anfang gedacht habe. 

    Zu deinem Fehler: Hast Du in deinem Projekt einen Ordner mit dem Namen Page angelegt und befinden sich darin Klassen im Namespace Page. Wenn ja dann ist hier auch der Fehler. Page ist eigentlich eine Klasse (Windows.UI.Xaml.Controls.Page) in deinem Projekt scheinbar auch ein Namespace. Ich würde dir abraten Namen zu verwenden die das Framework oder die Programmiersprache nutzt. Du kannst aber natürlich sowas wie MyPages nutzen.

    Bei meinem Beispiel oben ist der Converter nur für TwoWay nötig. Einen Converter braucht man nur wenn man einen Type ändern will. Ich erwarte aber das in SelectedItem das BingLanguageItemViewModel drin ist. In jedem Fall wird auch das ViewModel zugewiesen.

    Bei x:Bind müsste das Property in der CodeBehind existieren. Wie im Beispiel BingLanguageViewModel.SelectedItem. Nur das es dann nur ein string wäre. Ein ItemTemplate macht nur bei Controls mit ItemSource sinn. Damit wird Xaml gesagt, das er hier eine Liste abarbeiten muss und für jeden Eintag in der Liste ein Control mit Daten erzeugen soll.


    Gruß Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP

    Cross Platform Canvas for UWP, Android, iOS

    UWP Community Toolkit Sample App

    Alle Größenangaben in UWP müssen durch 4 teilbar sein

    Samstag, 4. November 2017 19:06
  • Hallo Thomas, Forum,

    ich habe in diesem Zusammenhang noch eine Frage. Dazu das folgende Schema zum Erklären:

    Vorab: Das ganze habe ich bereits auf der MainPage aufgebaut (läuft).

    Ich möchte alles nun etwas modularer aufbauen und die Play/Pause (und weitere) Funktionen in einem UserControl unterbringen. Genauso wie die Playlist, die ebenfalls Funktionalität wie Sortierung nach Metadaten etc. mitbringt.

    Nun zu den violetten Kästen:Wenn ich Daten in der App.cs verfügbar mache, kann ich sie recht einfach auf jeder Seite/UserControll via Binding darstellen. Ist das der richtige Weg? Es fühlt sich irgendwie nicht richtig an - ich würde das lieber auf der MainPage umsetzen, bzw. in den UserControls oder in separaten Klassen. Sehe ich es richtig, dass ich die Songliste bspw. auf der MainPage.cs erstellen kann und sie dann im UserControl mittels Binding und RelativeSource von der MainPage ziehen kann?

    Nun möchte ich den Play-Button, bzw. ein Item aus dem GridView (beides UserControls) drücken und ein Song soll im MediaElement gestartet werden. Wo befindet sich das MediaElement am besten? Am Ende lande ich wieder bei der oder einer ähnlichen Frage zu Beginn dieses Threads: Wie greife ich auf eine Funktion auf einer andern Seite/UserControl zu...

    Oder ist so ein Konzept nicht zielführend und ich sollte alles wieder auf die MainPage packen? :)  Mit allen anderen Funktionen, die ich hier nicht nenne, ist der Code bei 1000 Zeilen recht unübersichtlich ;)

    Gruß René


    [EDIT] Die Musikliste steht u.a. stellvertretend für andere Parameter/Einstellungen, die für die ganze App, also mehrere Seiten zur Verfügung stehen können. Das Laden der Musikliste in der App.cs ist auch in sofern von Nachteil, dass der User eigentlich nach dem Aufbau der Seite via ProgressRing sehen soll, dass geladen wird. Andernfalls dauert das Laden der App vermutlich so lang, bis die Liste erstellt ist (und das dauert ein paar Sekunden)
    • Bearbeitet _Queequack_ Mittwoch, 22. November 2017 05:26
    Dienstag, 21. November 2017 20:05
  • Hallo René,

    in der App.cs würde ich da nicht machen. Ich würde ein ViewModel anlegen. Dieses dann entweder über ein Singelton oder ein statisches Property zur Verfügung stellen. Auf diese so erzeugte Klasse kann dann jedes UserControl und jede weiter Page zugreifen. 

    Ich habe mal nach deinem Beispiel oben ein App mit ViewModel erstellt. Um es zu testen, muss Du noch ein mp3 Lied in den Assets Ordner packen und es Track01.mp3 nennen. Das Projekt findest Du auf GitHub 


    Gruß Thomas

    Sage nie, ich kann es nicht - sage nur, ich kann es noch nicht!

    Icon für UWP

    Cross Platform Canvas for UWP, Android, iOS

    UWP Community Toolkit Sample App

    Alle Größenangaben in UWP müssen durch 4 teilbar sein

    • Als Antwort markiert _Queequack_ Samstag, 30. Dezember 2017 12:46
    Freitag, 24. November 2017 14:49
  • Hallo Thomas,

    vielen, vielen Dank dafür! Das sieht sehr überschaubar aus und es hilft mir ungemein weiter! 

    Gruß René

    Samstag, 30. Dezember 2017 12:46
  • Hallo Thomas,

    ich habe meine App nun grundlegend neu geschrieben, sieht super aus. Ich versuche jetzt in dem UserControl einen ProgressBar und u.a. den Max Value des Mp3s anzuzeigen (mittels x:Bind). Das habe ich bisher auf der MainPage mit den Eigenschaften des Mediaelements gemacht (Max... Mp3MediaElement.NaturalDuration.TimeSpan.TotalSeconds, aktuelle Position... Mp3MediaElement.Position). 

    Das MediaElement ist immer noch auf der MainPage. Kann ich die Eigenschaften davon irgendwie für die UserControls verfügbar machen?

    Gruß René

    Dienstag, 9. Januar 2018 09:17
  • Hallo René,

    du kannst einen Verweis des Mediacontrols im UserControl speichern... Stichwort DependencyProperty

    oder eine statische Instanz der MainPage anlegen. Über die kannst du dann die public Elemente ansprechen

    Ich hoffe das hilft dir soweit...

    P.S.: hört sich spannend an, was du da machst ;)


    JC-DESIGN

    Dienstag, 9. Januar 2018 09:34
  • Hallo JC-Design,

    danke für den Hinweis. 

    Würde die DependencyProperty bedeuten, dass ich einen Wert in der MainPage.xaml.cs habe, der sich ändern kann - diesen kann ich dann analog in meinem UserControl abrufen und bspw. im TextBlock dort binden. Ähnelich dem: LINK?

    Ich habe noch nicht herausgefunden, wie ich bspw. die aktuelle Position des abgespielten Songs herausfinde. Ich kann einen Timer machen und anhand dessen immer wieder eine Variable aktualisieren. Ich kann mir vorstellen, dass das auch anders geht?

    Gruß René

    Dienstag, 9. Januar 2018 11:04
  • Wie im Link beschrieben sollte das gut Funktionieren. Dann hast du alle Details in deinem UserControl

    Was die Position angeht, würde ich das auch über einen Timer lösen. Jede Sekunde den Wert aktualisieren... und je nachdem welche Funktionen benutzt werden (start/stop/...) muss der Timer gestartet oder gestoppt werden...


    JC-DESIGN

    Dienstag, 9. Januar 2018 11:21