none
UWP Binding wird nur bedingt dargestellt RRS feed

  • Frage

  • Hallo Forum, sorry für den Titel, aber ich finde keinen besseren...

    Ich beziehe via API-Abruf Wetterdaten: Aktuelles Wetter und Forecast (2 verschiedene Abrufe). In einem kleinen Programm OHNE BINDINGS funktioniert das wunderbar. Jetzt wollte ich das Ganze in meine "Produktivumgebung" MIT BINDINGS einbinden. Rufe ich eine der beiden APIs ab, funktioniert das Binding einwandfrei. Rufe ich allerdings beide nacheinander ab, werden die Textblöcke nicht mehr aktualisiert. Die Inhalte sind vorhanden, wie beim Einzelabruf. Ich vermute einen Fehler beim Binding... Reduziert dargestellt (ohne Klassenbeschreibung, JsonSerializer etc...).

    Die Textblöcke lasse ich bei meinen Tests unverändert. 

    <TextBlock Name="TEMP_CURRENT_TextBlock" Text="{x:Bind WeatherViewModel.WeatherData.WeatherData_current_Temperature, Mode=OneWay}" />
    
    <TextBlock Name="TEMP_FORECAST_TextBlock" Text="{x:Bind WeatherViewModel.WeatherData.WeatherData_forecast_Temperature, Mode=OneWay}" />


    Beim Datensammeln kommentiere ich lediglich die eine oder andere "GetWeather" Funktion (hier werden Koordinaten mitgeschickt), sowie die zugehörige Variablenzuweisung aus/ein. In jedem Fall bekomme ich erwünschten Daten aus den Funktionen heraus. Nur werden diese nicht in der UI angezeigt (sofern ich beide abrufe). Ich habe auch versucht einen delay einzubauen (await Task.Delay(1000)), ohne Erfolg. Ich habe auch versucht ein paar Namen zu ändern, aber es kommt eigentlich kein Name doppelt vor. 

    public async void WeatherUpdate() { try { Model.RootObject_FORECAST weatherData_forecast = await Model.OpenWeatherMap_FORECAST.GetWeather(99.99999, 9.99999);

    WeatherData.WeatherData_forecast_Temperature = Math.Round(weatherData_forecast.list[0].temp.min, 0, MidpointRounding.AwayFromZero).ToString() + "°"; Model.RootObject_CURRENT weatherData_current = await Model.OpenWeatherMap_CURRENT.GetWeather(99.99999, 9.99999); WeatherData.WeatherData_current_Temperature = Math.Round(weatherData_current.main.temp, 1, MidpointRounding.AwayFromZero).ToString("0.0") + "°C"; } catch {} }

    Der Vollständigkeit halber die Funktion für den API-Abruf als Beispiel. Koordinaten und meine ID sind unkenntlich gemacht (ich sehe gerade, dass die übergebenen Koordinaten gar nicht aktiv eingebunden werden... wie dem auch sei...).

        public class OpenWeatherMap_CURRENT
        {
            public async static Task<RootObject_CURRENT> GetWeather(double lat, double lon)
            {
                var http = new HttpClient();
                var response = await http.GetAsync("http://api.openweathermap.org/data/2.5/weather?lat=99.99999&lon=9.99999&appid=1234567890987654321d&units=metric&lang=de");
                var result = await response.Content.ReadAsStringAsync();
                var serializer = new DataContractJsonSerializer(typeof(RootObject_CURRENT));
                var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
                var data = (RootObject_CURRENT)serializer.ReadObject(ms);
                return data;
            }
        }

    Gruß René

    Dienstag, 26. Juni 2018 19:12

Antworten

  • Hallo René,

    erstmal bindet man kein Model an die View, nur ViewModels werden gebunden. Das heißt auch das man die Daten vom Model im ViewModel "umpackt". Das mag vielleicht etwas sinnlos erscheinen (Ich fand das am Anfang recht sinnlos) hat aber ein guten Grund. Erst im ViewModel wird INotifyPropertyChanged eingeführt, dennoch wird das Model weiter als "Datenhaltung" verwendet.

    Hier das geänderte WeatherViewModel. Alles was ich geändert habe ist mit "Meine Änderungen" gekennzeichnet

    namespace Wetter_aktuelleUNDforecast_BINDING.ViewModel
    {
        public class WeatherViewModel : INotifyPropertyChanged
        {
            Model.WeatherData _WeatherData;
            public Model.WeatherData WeatherData
            {
                get { return _WeatherData; }
                set
                {
                    _WeatherData = value;
                    RaisePropertyChanged("WeatherData");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
    
            #region Meine Änderungen
    
            public string WeatherData_current_Temperature
            {
                get { return WeatherData.WeatherData_current_Temperature; }
                set { WeatherData.WeatherData_current_Temperature = value; RaisePropertyChanged(nameof(WeatherData_current_Temperature)); }
            }
    
            public string WeatherData_current_Description
            {
                get { return WeatherData.WeatherData_current_Description; }
                set { WeatherData.WeatherData_current_Description = value; RaisePropertyChanged(nameof(WeatherData_current_Description)); }
            }
    
            public BitmapImage WeatherData_current_Icon
            {
                get { return WeatherData.WeatherData_current_Icon; }
                set { WeatherData.WeatherData_current_Icon = value; RaisePropertyChanged(nameof(WeatherData_current_Icon)); }
            }
    
            public string WeatherData_forecast_Day0_Temperature_min
            {
                get { return WeatherData.WeatherData_forecast_Day0_Temperature_min; }
                set { WeatherData.WeatherData_forecast_Day0_Temperature_min = value; RaisePropertyChanged(nameof(WeatherData_forecast_Day0_Temperature_min)); }
            }
    
            public string WeatherData_forecast_Day0_Temperature_max
            {
                get { return WeatherData.WeatherData_forecast_Day0_Temperature_max; }
                set { WeatherData.WeatherData_forecast_Day0_Temperature_max = value; RaisePropertyChanged(nameof(WeatherData_forecast_Day0_Temperature_max)); }
            }
    
            #endregion
    
            public async Task Init()
            {
                WeatherData = new Model.WeatherData();
                WeatherUpdate();
            }
    
            static int count = 0;
    
            public async void WeatherUpdate()
            {
                count++;
    
                double latitude = 44.47288;
                double longitude = -71.17626;
                string APIid = "1234567890987654321abcdefghijklm";
    
                try
                {
    
                    // BLOCK A
                    //Model.RootObject_FORECAST weatherData_forecast = await Model.OpenWeatherMap_FORECAST.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = Math.Round(weatherData_forecast.list[0].temp.min, 0, MidpointRounding.AwayFromZero).ToString() + "°";
    
                    // BLOCK B
                    //Model.RootObject_CURRENT weatherData_current = await Model.OpenWeatherMap_CURRENT.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_current_Temperature = Math.Round(weatherData_current.main.temp, 1, MidpointRounding.AwayFromZero).ToString("0.0") + "°C";
                    //WeatherData.WeatherData_current_Description = weatherData_current.weather[0].description.ToString();
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/{0}.png", weatherData_current.weather[0].icon));
                    //WeatherData.WeatherData_current_Icon = image;
                    //Debug.WriteLine(WeatherData.WeatherData_current_Temperature);
                    //Debug.WriteLine(WeatherData.WeatherData_current_Description);
                    //Debug.WriteLine(image.UriSource);
    
                    // BLOCK C - MANUELL
                    //WeatherData.WeatherData_current_Temperature = $"99°C-{count}";
                    //WeatherData.WeatherData_current_Description = $"Test-{count}";
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = $"12°C-{count}";
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    //WeatherData.WeatherData_current_Icon = image;
    
                    //Meine Änderungen
                    WeatherData_current_Temperature = $"99°C-{count}";
                    WeatherData_current_Description = $"Test-{count}";
                    WeatherData_forecast_Day0_Temperature_min = $"12°C-{count}";
                    BitmapImage image = new BitmapImage();
                    image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    WeatherData_current_Icon = image;
                }
    
                catch
                {
    
                }
    
            }
        }
    }


    WeatherUC.xaml habe ich auch geändert. Alle Werte verweisen nur noch aufs ViewModel

    <Grid Background="DimGray">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
    
            <RelativePanel Grid.Row="2">
                <RelativePanel Name="WeatherMainTempPanel" RelativePanel.AlignRightWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
                    <TextBlock Name="Weather_Current_Temperature_TextBlock" RelativePanel.AlignRightWithPanel="True"
                                Text="{x:Bind WeatherViewModel.WeatherData_current_Temperature, Mode=OneWay}"
                               Width="125" FontSize="41" Foreground="White" TextAlignment="Right" />
                    <Image Name="Weather_Current_Image" Width="50" Height="50" RelativePanel.LeftOf="Weather_Current_Temperature_TextBlock" 
                           Source="{x:Bind WeatherViewModel.WeatherData_current_Icon, Mode=OneWay}"
                           RelativePanel.AlignVerticalCenterWith="Weather_Current_Temperature_TextBlock"/>
                </RelativePanel>
                <TextBlock Name="Weather_Current_Description_TextBlock" Foreground="White" 
                           Text="{x:Bind WeatherViewModel.WeatherData_current_Description, Mode=OneWay}" 
                           RelativePanel.AlignVerticalCenterWith="Weather_Current_Max_Min_Grid" RelativePanel.LeftOf="Weather_Current_Max_Min_Grid" />
                <Grid Name="Weather_Current_Max_Min_Grid"  HorizontalAlignment="Right" RelativePanel.Below="WeatherMainTempPanel" RelativePanel.AlignRightWithPanel="True">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="30"/>
                        <ColumnDefinition Width="30"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Name="Weather_Forecast_Day0_Temperature_min_TextBlock" 
                               Text="{x:Bind WeatherViewModel.WeatherData_forecast_Day0_Temperature_min, Mode=OneWay}" 
                               Foreground="SteelBlue" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
                    <TextBlock Name="Weather_Forecast_Day0_Temperature_max_TextBlock" 
                               Text="{x:Bind WeatherViewModel.WeatherData_forecast_Day0_Temperature_max, Mode=OneWay}" 
                               Foreground="Peru" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center"/>
                </Grid>
            </RelativePanel>
            <Button Name="WeatherUpdate_Button" Content="UPDATE" Click="WeatherUpdate_Button_Click" Grid.Row="4" HorizontalAlignment="Right"/>
        </Grid>

    Das ViewModel dient nun als Schnittstelle zwischen Model und View


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings


    Sonntag, 1. Juli 2018 15:15

Alle Antworten

  • Hi René,
    was es da für ein Problem bei Dir gibt, kann man aus den dargestellten Details nicht erkennen. Du solltest mal ein paar Debug.Print einbauen. Mit der folgenden Demo kann ich Dein Problem nicht reproduzieren:

    XAML:

    <Page
        x:Class="App1.Page09"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <StackPanel>
        <TextBlock Name="TEMP_CURRENT_TextBlock" Text="{x:Bind ViewModel.WeatherData_current_Temperature, Mode=OneWay}" />
        <TextBlock Name="TEMP_FORECAST_TextBlock" Text="{x:Bind ViewModel.WeatherData_forecast_Temperature, Mode=OneWay}" />
        <Button Content="Laden" Click="Button_Click" />
      </StackPanel>
    </Page>

    Dazu der Code:

    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    namespace App1
    {
      public sealed partial class Page09 : Page
      {
        public Page09()
        {
          this.InitializeComponent();
        }
        public Page09VM ViewModel { get; set; } = new Page09VM();
    
        private void Button_Click(object sender, RoutedEventArgs e) => ViewModel.LoadData();
      }
      public class Page09VM : INotifyPropertyChanged
      {
        string _weatherData_current_Temperature;
        public string WeatherData_current_Temperature
        {
          get => _weatherData_current_Temperature;
          set { _weatherData_current_Temperature = value; OnPropertyChanged(); }
        }
    
        string _weatherData_forecast_Temperature;
        public string WeatherData_forecast_Temperature
        {
          get => _weatherData_forecast_Temperature;
          set { _weatherData_forecast_Temperature = value; OnPropertyChanged(); }
        }
    
        internal async void LoadData()
        {
          WeatherData_current_Temperature = await WeatherUpdate("Anzeige 1");
          WeatherData_forecast_Temperature = await WeatherUpdate("Anzeige 2");
        }
    
        internal async Task<string> WeatherUpdate(string par)
        {
          return await Task<string>.Run(async () =>
          {
            await Task.Delay(2000);
            return par;
          });
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    }


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Dienstag, 26. Juni 2018 20:53
  • Hallo Peter,

    danke für die Rückmeldung! Ich wollte eigentlich gar nicht mit einem Delay arbeiten und ich möchte sehr gerne den Fehler verstehen. Ich habe das Programm mal auf das Wesentliche reduziert und dabei die Struktur gleich gelassen. Da ich Daten UC-übergreifend verfügbar machen möchte, habe ich ein GlobalAppModel eingeführt. Das wird in der App.xaml.cs initiiert.

    Das abgespeckte Programm habe ich mal in einem Zip-File hier hochgeladen: DropBox Download

    Zur Übersicht ein kleiner Screenshot:

    Ich kann das Bild, was sich mir mit meinem „Produktivprogramm“ bot, auch nicht reproduzieren. Einen/den Fehler (Bindings funktionieren nicht) habe ich dennoch, daher denke ich, hiermit lässt sich das auch lösen. Ich war mir nicht ganz sicher, ob es was mit dem Main- und Nebenthread zu tun hat. Daher habe ich es auch mal mit einem dispatcher probiert, ohne Erfolg:

    try
       {
          var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
          await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
              {
                 // BLOCK B
                 //…
              });
       }

    Ich habe die WeatherData überwacht (auch Debug.writelines eingebaut). Die Werte sind vorhanden, werden problemlos in WeatherData abgelegt, sie werden jedoch nicht mittels Binding in der UC dargestellt. Also habe ich dasselbe ohne die GetWeatherfunktion ausprobiert (siehe // BLOCK C - MANUELL). Damit funktioniert das Binding.

    Kurz zusammengefasst: Ich möchte die Daten mit Block A und Block B ziehen. Block C zeigt, dass das Binding theoretisch funktioniert. Ich muss die API ID leider ersetzen. Die Koordinaten sind von Berlin.

    public async void WeatherUpdate()
            {
                double latitude = 44.47288;
                double longitude = -71.17626;
                string APIid = "1234567890987654321abcdefghijklm";
    
                try
                {
    
                    // BLOCK A
                    //Model.RootObject_FORECAST weatherData_forecast = await Model.OpenWeatherMap_FORECAST.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = Math.Round(weatherData_forecast.list[0].temp.min, 0, MidpointRounding.AwayFromZero).ToString() + "°";
    
                    // BLOCK B
                    //Model.RootObject_CURRENT weatherData_current = await Model.OpenWeatherMap_CURRENT.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_current_Temperature = Math.Round(weatherData_current.main.temp, 1, MidpointRounding.AwayFromZero).ToString("0.0") + "°C";
                    //WeatherData.WeatherData_current_Description = weatherData_current.weather[0].description.ToString();
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/{0}.png", weatherData_current.weather[0].icon));
                    //WeatherData.WeatherData_current_Icon = image;
                    //Debug.WriteLine(WeatherData.WeatherData_current_Temperature);
                    //Debug.WriteLine(WeatherData.WeatherData_current_Description);
                    //Debug.WriteLine(image.UriSource);
    
                    // BLOCK C - MANUELL
                    WeatherData.WeatherData_current_Temperature = "99°C";
                    WeatherData.WeatherData_current_Description = "TEST";
                    WeatherData.WeatherData_forecast_Day0_Temperature_min = "12°C";
                    BitmapImage image = new BitmapImage();
                    image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    WeatherData.WeatherData_current_Icon = image;
                }
    
                catch
                {
    
                }
    
            }
    

    Die Funktion dahinter ist die gleiche wie bisher:

    namespace Wetter_aktuelleUNDforecast_BINDING.Model
    {
        public class WeatherData
        {
            public string WeatherData_current_Temperature { get; set; }
            public string WeatherData_current_Description { get; set; }
            public BitmapImage WeatherData_current_Icon { get; set; }
            public string WeatherData_forecast_Day0_Temperature_min { get; set; }
            public string WeatherData_forecast_Day0_Temperature_max { get; set; }
        }

    public class OpenWeatherMap_CURRENT { public async static Task<RootObject_CURRENT> GetWeather(double lat, double lon, string apiID) { var http = new HttpClient(); var url = String.Format("http://api.openweathermap.org/data/2.5/weather?lat={0}&lon={1}&appid={2}&units=metric&lang=de", lat, lon, apiID); var response = await http.GetAsync(url); var result = await response.Content.ReadAsStringAsync(); var serializer = new DataContractJsonSerializer(typeof(RootObject_CURRENT)); var ms = new MemoryStream(Encoding.UTF8.GetBytes(result)); var data = (RootObject_CURRENT)serializer.ReadObject(ms); return data; } }

    ...

    Dasselbe für Model.RootObject_FORECAST. mit entsprechender API.

    Gruß René

    Sonntag, 1. Juli 2018 09:34
  • Hallo Renè

    ändere mal WeatherData wie folgt ab:

        public class TDatei : INotifyPropertyChanged
        {
            private int FNr;
            public int Nr
            {
                get { return FNr; }
                set
                {
                    if (FNr != value)
                    {
                        FNr = value;
                        NotifyPropertyChanged(nameof(Nr));
                    }
                }
            }
    
            private string FFn;
            public string Fn
            {
                get { return FFn; }
                set
                {
                    if (FFn != value)
                    {
                        FFn = value;
                        NotifyPropertyChanged(nameof(Fn));
                    }
                }
            }
    
            private TConstDateien.DateiAktion FAktion;
            public TConstDateien.DateiAktion Aktion
            {
                get { return FAktion; }
                set
                {
                    if (FAktion != value)
                    {
                        FAktion = value;
                        NotifyPropertyChanged(nameof(Aktion));
                    }
                }
            }
    
            private long FSize;
            public long Size
            {
                get { return FSize; }
                set
                {
                    if (FSize != value)
                    {
                        FSize = value;
                        NotifyPropertyChanged(nameof(Size));
                    }
                }
            }
    
            private DateTime FDate;
            public DateTime Date
            {
                get { return FDate; }
                set
                {
                    if (FDate != value)
                    {
                        FDate = value;
                        NotifyPropertyChanged(nameof(Date));
                    }
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void NotifyPropertyChanged(string propName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }
    

            

     NotifyPropertyChanged benachrichtigt die TextBlöcke, das sich die Eigenschaften geändert haben.   

    Gruß Klaus.

    Sonntag, 1. Juli 2018 10:16
  • Hallo Klaus,

    vielen Dank für deine Antwort. Ich verwende bereits INotifyPropertyChanged

    Im namespace Wetter_aktuelleUNDforecast_BINDING.Model befindet sich die public class WeatherData mit ihren Eigenschaften.

    Im namespace Wetter_aktuelleUNDforecast_BINDING.ViewModel erstelle ich ein Objekt des Typs WeatherData von oben. Und im erstellten Objekt überwache ich die Änderungen:

    namespace Wetter_aktuelleUNDforecast_BINDING.ViewModel
    {
        public class WeatherViewModel : INotifyPropertyChanged
        {
            Model.WeatherData _WeatherData;
            public Model.WeatherData WeatherData
            {
                get { return _WeatherData; }
                set
                {
                    _WeatherData = value;
                    RaisePropertyChanged("WeatherData");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
    
            public async Task Init()
            {
                WeatherData = new Model.WeatherData();
                WeatherUpdate();
            }
    
            public async void WeatherUpdate()
            {
                double latitude = 44.47288;
                double longitude = -71.17626;
                string APIid = "1234567890987654321abcdefghijklm";
    
                try
                {
    
                    // BLOCK A
                    //Model.RootObject_FORECAST weatherData_forecast = await Model.OpenWeatherMap_FORECAST.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = Math.Round(weatherData_forecast.list[0].temp.min, 0, MidpointRounding.AwayFromZero).ToString() + "°";
    
                    // BLOCK B
                    Model.RootObject_CURRENT weatherData_current = await Model.OpenWeatherMap_CURRENT.GetWeather(latitude, longitude, APIid);
                    WeatherData.WeatherData_current_Temperature = Math.Round(weatherData_current.main.temp, 1, MidpointRounding.AwayFromZero).ToString("0.0") + "°C";
                    WeatherData.WeatherData_current_Description = weatherData_current.weather[0].description.ToString();
                    BitmapImage image = new BitmapImage();
                    image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/{0}.png", weatherData_current.weather[0].icon));
                    WeatherData.WeatherData_current_Icon = image;
                    Debug.WriteLine(WeatherData.WeatherData_current_Temperature);
                    Debug.WriteLine(WeatherData.WeatherData_current_Description);
                    Debug.WriteLine(image.UriSource);
    
                    // BLOCK C - MANUELL
                    //WeatherData.WeatherData_current_Temperature = "99°C";
                    //WeatherData.WeatherData_current_Description = "TEST";
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = "12°C";
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    //WeatherData.WeatherData_current_Icon = image;
                }
    
                catch
                {
    
                }
    
            }
        }
    }

    Gruß René

    Sonntag, 1. Juli 2018 12:26
  • Hallo René,

    erstmal bindet man kein Model an die View, nur ViewModels werden gebunden. Das heißt auch das man die Daten vom Model im ViewModel "umpackt". Das mag vielleicht etwas sinnlos erscheinen (Ich fand das am Anfang recht sinnlos) hat aber ein guten Grund. Erst im ViewModel wird INotifyPropertyChanged eingeführt, dennoch wird das Model weiter als "Datenhaltung" verwendet.

    Hier das geänderte WeatherViewModel. Alles was ich geändert habe ist mit "Meine Änderungen" gekennzeichnet

    namespace Wetter_aktuelleUNDforecast_BINDING.ViewModel
    {
        public class WeatherViewModel : INotifyPropertyChanged
        {
            Model.WeatherData _WeatherData;
            public Model.WeatherData WeatherData
            {
                get { return _WeatherData; }
                set
                {
                    _WeatherData = value;
                    RaisePropertyChanged("WeatherData");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
    
            #region Meine Änderungen
    
            public string WeatherData_current_Temperature
            {
                get { return WeatherData.WeatherData_current_Temperature; }
                set { WeatherData.WeatherData_current_Temperature = value; RaisePropertyChanged(nameof(WeatherData_current_Temperature)); }
            }
    
            public string WeatherData_current_Description
            {
                get { return WeatherData.WeatherData_current_Description; }
                set { WeatherData.WeatherData_current_Description = value; RaisePropertyChanged(nameof(WeatherData_current_Description)); }
            }
    
            public BitmapImage WeatherData_current_Icon
            {
                get { return WeatherData.WeatherData_current_Icon; }
                set { WeatherData.WeatherData_current_Icon = value; RaisePropertyChanged(nameof(WeatherData_current_Icon)); }
            }
    
            public string WeatherData_forecast_Day0_Temperature_min
            {
                get { return WeatherData.WeatherData_forecast_Day0_Temperature_min; }
                set { WeatherData.WeatherData_forecast_Day0_Temperature_min = value; RaisePropertyChanged(nameof(WeatherData_forecast_Day0_Temperature_min)); }
            }
    
            public string WeatherData_forecast_Day0_Temperature_max
            {
                get { return WeatherData.WeatherData_forecast_Day0_Temperature_max; }
                set { WeatherData.WeatherData_forecast_Day0_Temperature_max = value; RaisePropertyChanged(nameof(WeatherData_forecast_Day0_Temperature_max)); }
            }
    
            #endregion
    
            public async Task Init()
            {
                WeatherData = new Model.WeatherData();
                WeatherUpdate();
            }
    
            static int count = 0;
    
            public async void WeatherUpdate()
            {
                count++;
    
                double latitude = 44.47288;
                double longitude = -71.17626;
                string APIid = "1234567890987654321abcdefghijklm";
    
                try
                {
    
                    // BLOCK A
                    //Model.RootObject_FORECAST weatherData_forecast = await Model.OpenWeatherMap_FORECAST.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = Math.Round(weatherData_forecast.list[0].temp.min, 0, MidpointRounding.AwayFromZero).ToString() + "°";
    
                    // BLOCK B
                    //Model.RootObject_CURRENT weatherData_current = await Model.OpenWeatherMap_CURRENT.GetWeather(latitude, longitude, APIid);
                    //WeatherData.WeatherData_current_Temperature = Math.Round(weatherData_current.main.temp, 1, MidpointRounding.AwayFromZero).ToString("0.0") + "°C";
                    //WeatherData.WeatherData_current_Description = weatherData_current.weather[0].description.ToString();
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/{0}.png", weatherData_current.weather[0].icon));
                    //WeatherData.WeatherData_current_Icon = image;
                    //Debug.WriteLine(WeatherData.WeatherData_current_Temperature);
                    //Debug.WriteLine(WeatherData.WeatherData_current_Description);
                    //Debug.WriteLine(image.UriSource);
    
                    // BLOCK C - MANUELL
                    //WeatherData.WeatherData_current_Temperature = $"99°C-{count}";
                    //WeatherData.WeatherData_current_Description = $"Test-{count}";
                    //WeatherData.WeatherData_forecast_Day0_Temperature_min = $"12°C-{count}";
                    //BitmapImage image = new BitmapImage();
                    //image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    //WeatherData.WeatherData_current_Icon = image;
    
                    //Meine Änderungen
                    WeatherData_current_Temperature = $"99°C-{count}";
                    WeatherData_current_Description = $"Test-{count}";
                    WeatherData_forecast_Day0_Temperature_min = $"12°C-{count}";
                    BitmapImage image = new BitmapImage();
                    image.UriSource = new Uri(String.Format("ms-appx:///Assets/Weather/09d.png"));
                    WeatherData_current_Icon = image;
                }
    
                catch
                {
    
                }
    
            }
        }
    }


    WeatherUC.xaml habe ich auch geändert. Alle Werte verweisen nur noch aufs ViewModel

    <Grid Background="DimGray">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
    
            <RelativePanel Grid.Row="2">
                <RelativePanel Name="WeatherMainTempPanel" RelativePanel.AlignRightWithPanel="True" RelativePanel.AlignLeftWithPanel="True">
                    <TextBlock Name="Weather_Current_Temperature_TextBlock" RelativePanel.AlignRightWithPanel="True"
                                Text="{x:Bind WeatherViewModel.WeatherData_current_Temperature, Mode=OneWay}"
                               Width="125" FontSize="41" Foreground="White" TextAlignment="Right" />
                    <Image Name="Weather_Current_Image" Width="50" Height="50" RelativePanel.LeftOf="Weather_Current_Temperature_TextBlock" 
                           Source="{x:Bind WeatherViewModel.WeatherData_current_Icon, Mode=OneWay}"
                           RelativePanel.AlignVerticalCenterWith="Weather_Current_Temperature_TextBlock"/>
                </RelativePanel>
                <TextBlock Name="Weather_Current_Description_TextBlock" Foreground="White" 
                           Text="{x:Bind WeatherViewModel.WeatherData_current_Description, Mode=OneWay}" 
                           RelativePanel.AlignVerticalCenterWith="Weather_Current_Max_Min_Grid" RelativePanel.LeftOf="Weather_Current_Max_Min_Grid" />
                <Grid Name="Weather_Current_Max_Min_Grid"  HorizontalAlignment="Right" RelativePanel.Below="WeatherMainTempPanel" RelativePanel.AlignRightWithPanel="True">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="30"/>
                        <ColumnDefinition Width="30"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Name="Weather_Forecast_Day0_Temperature_min_TextBlock" 
                               Text="{x:Bind WeatherViewModel.WeatherData_forecast_Day0_Temperature_min, Mode=OneWay}" 
                               Foreground="SteelBlue" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
                    <TextBlock Name="Weather_Forecast_Day0_Temperature_max_TextBlock" 
                               Text="{x:Bind WeatherViewModel.WeatherData_forecast_Day0_Temperature_max, Mode=OneWay}" 
                               Foreground="Peru" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Center"/>
                </Grid>
            </RelativePanel>
            <Button Name="WeatherUpdate_Button" Content="UPDATE" Click="WeatherUpdate_Button_Click" Grid.Row="4" HorizontalAlignment="Right"/>
        </Grid>

    Das ViewModel dient nun als Schnittstelle zwischen Model und View


    Gruß Thomas
    13 Millionen Schweine landen jährlich im Müll
    Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings


    Sonntag, 1. Juli 2018 15:15
  • ... Ich wollte eigentlich gar nicht mit einem Delay arbeiten und ich möchte sehr gerne den Fehler verstehen. ...

    Hi René,
    das Delay habe ich nur zur Simulation der Verzögerung beim Abruf eingebaut.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Montag, 2. Juli 2018 15:02