none
Flyout-Auswahl RRS feed

  • Frage

  • Hi Peter

    bei mir ist ein neues Problem aufgetaucht, meine viele Buttons haben auch noch jeweils ein Flyout als Eingabemöglichkeit für Daten, das klappt auch. Da meine Buttons aber auf zwei Zustände programmiert sind (PrgMode: Eingabe der Hintergrunddaten die der Button im EigMode: Abruft) brauche ich noch ein zweites Flyout.

    Beide Flyouts habe ich als StaticResourse angelegt im XML angelegt. Würde jetzt gerne, auch über einen Converter, die entsprechenden Flyouts (PrgMode, EngMode (beide bool Variablen sind mit NPC angelegt und funktionieren) auswählen. Hab aber kein entsprechender Converter gefunden (BoolenToVisibility habe ich in AppUiBasics  gefunden). Für einen Tipp währe ich dankbar.

    Viele Grüsse

    Bernd Geiger 

    Mittwoch, 21. Oktober 2015 22:24

Antworten

  • Hi Bernd,
    ich will Dich nicht demotivieren.

    Das Problem des Konverters besteht darin, dass er eine Instanz eines Flyouts in Abhängigkeit eines Wertes liefern muss. Der Konverter kennt nicht die Page, in welcher er genutzt wird. Deshalb kann er auch nicht ein Flyout auswählen, welches in den Ressourcen der Page deklariert ist. Der Konverter befindet sich jedoch in der Application und kann deshalb ein Flyout auswählen, welches sich in der Application befindet (im App.xaml). Wenn der Konverter aber unbedingt ein Flyout auswählen soll, welches in der Page deklariert ist, muss der Konverter eine Information bekommen, um auf die Flyouts zugreifen zu können (Flyouts als Parameter bzw. Bindung oder Verweis auf die Page).

    Da bei der Nutzung von MVVM der ViewModel weder auf "Name", noch auf "Tag" zugreifen kann, da er das Objekt nicht kennt, benötigst Du kein "Name" und auch kein "Tag". Beim Button kann man eine ICommand-Eigenschaft im ViewModel binden und zusätzlich das Element aus der Collection. Damit steht im Command-Ereignis das Element zur Verfügung.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert GeigerBernd Samstag, 24. Oktober 2015 21:08
    • Tag als Antwort aufgehoben GeigerBernd Montag, 26. Oktober 2015 21:17
    • Als Antwort markiert GeigerBernd Montag, 26. Oktober 2015 21:17
    Samstag, 24. Oktober 2015 19:15
  • Hi Bernd,
    mit MVVM geht das auch recht einfach. Hier mal eine Demo dazu in C#.NET:

    Oberflächen-XAML:

    <Page
        x:Class="BlankApp01CS.Page01"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01CS"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
      <Page.Resources>
        <local:Page01Conv x:Key="conv"/>
        <DataTemplate x:Key="Page01ListViewTemplate">
          <StackPanel Orientation="Horizontal" Margin="10,0,0,0">
            <Button Content="Klick Flyout" Flyout="{Binding Switch, Converter={StaticResource conv}}" />
            <TextBlock Text="{Binding Info1}" Margin="5"/>
            <TextBlock Text="{Binding Info2}" Margin="5"/>
          </StackPanel>
        </DataTemplate>
        <local:Page01VM x:Key="vm"/>
      </Page.Resources>
      <Grid DataContext="{Binding Source={StaticResource vm}}"
            Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{Binding View}" 
                  ItemTemplate="{StaticResource Page01ListViewTemplate}"/>
      </Grid>
    </Page>

    Dazu die Flyouts im App.xaml:

    <Application
        x:Class="BlankApp01CS.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01CS">
      <Application.Resources>
        <Flyout x:Key="Page01FlyoutA">
          <Grid Background="Red">
            <StackPanel Margin="10">
              <TextBox Text="{Binding Info1, Mode=TwoWay}"/>
              <TextBox Text="{Binding Info2, Mode=TwoWay}"/>
            </StackPanel>
          </Grid>
        </Flyout>
        <Flyout x:Key="Page01FlyoutB">
          <Grid Background="Green">
            <StackPanel Margin="10">
              <TextBox Text="{Binding Info1, Mode=TwoWay}"/>
              <TextBox Text="{Binding Info2, Mode=TwoWay}"/>
            </StackPanel>
          </Grid>
        </Flyout>
      </Application.Resources>
    </Application>

    Und dann noch der ViewModel, Daten-Klasse und Konverter:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using Windows.UI.Xaml.Data;
    
    namespace BlankApp01CS
    {
      class Page01VM
      {
        CollectionViewSource cvs;
        ObservableCollection<Page01Data> col;
        Random rnd = new Random();
    
        public ICollectionView View
        {
          get
          {
            if (cvs == null)
            {
              col = new ObservableCollection<Page01Data>();
              for (int i = 1; i < 10; i++)
              {
                col.Add(new Page01Data()
                {
                  Switch = (rnd.NextDouble() > .5),
                  Info1 = string.Format("Datensatz {0}", i),
                  Info2 = string.Format("Wert {0}", rnd.Next(1, 100))});
              }
              cvs = new CollectionViewSource();
              cvs.Source = col;
            }
            return cvs.View;
          }
        }
      }
    
      public class Page01Data : INotifyPropertyChanged
      {
        public bool Switch { get; set; }
    
        private string _info1;
        public string Info1
        {
          get
          {
            return this._info1;
          }
          set
          {
            if (this._info1 != value)
            {
              this._info1 = value;
              OnPropertyChanged();
            }
          }
        }
    
        private string _info2;
        public string Info2
        {
          get
          {
            return this._info2;
          }
          set
          {
            if (this._info2 != value)
            {
              this._info2 = value;
              OnPropertyChanged();
            }
          }
        }
    
        #region OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "")
        {
          if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        #endregion
      }
    
      public class Page01Conv : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
          var resA = App.Current.Resources["Page01FlyoutA"];
          var resB = App.Current.Resources["Page01FlyoutB"];
          return ((bool)value) ? resB : resA;
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
          throw new NotImplementedException();
        }
      }
    }


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert GeigerBernd Montag, 26. Oktober 2015 21:19
    Sonntag, 25. Oktober 2015 06:55

Alle Antworten

  • Hi Bernd,
    für neue Fragen sollte ein neuer Thread aufgemacht werden. Andere Mitleser profitieren dann davon.

    Ein Konverter hat zwei Methoden, um die beiden Richtungen - Ausgabe und Eingabe - zu bedienen. Für die Flyout-Auswahl wird keine Eingabe benötigt. Es reicht die Verarbeitung des gebundenen Wertes aus der Datenquelle, um dann der Oberfläche das gewünschte Objekt bereitzustellen. Das kann dann so aussehen:

    <Button Content="x" Flyout={Binding ...

    Als Pfad der Bindung wird der Name der Eigenschaft aus der Datenquelle angeben, dazu dann der Konverter und bei Bedarf auch noch Parameter für den Konverter. Der Konverter bekommt die Eigenschaft z.B. als Boolean und liefert ein Objekt vom Typ Flyout an die Flyout-Eigenschaft des Buttons. Da der Konverter auch den Aufrufer bekommt, kann er die gewünschte Ressource auswählen und zurückliefern.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Donnerstag, 22. Oktober 2015 06:39
  • Hi Peter

    hast du mir ein Programmierbeispiel für den FlyoutConverter. Habe schon verstanden was du meinst, bin aber noch nicht soweit, die Programmierung aus dem Ärmel zu schütteln.

    Viele Grüsse

    Bernd Geiger

    Donnerstag, 22. Oktober 2015 18:11
  • Hi Bernd,
    nachfolgend ein kleines Beispiel:

    App.xaml mit den Flyout-Ressourcen:

    <Application
        x:Class="BlankApp01VB.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01VB">
      <Application.Resources>
        <Flyout x:Key="Page01FlyoutA">
          <Button Content="Flyout A" Background="Red"/>
        </Flyout>
        <Flyout x:Key="Page01FlyoutB">
          <Button Content="Flyout B" Background="Green"/>
        </Flyout>
      </Application.Resources>
    </Application>
    

    XAML der Page:

    <Page
        x:Class="BlankApp01VB.Page01"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01VB"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
      <Page.Resources>
        <local:Page01VM x:Key="vm"/>
        <local:Page01Conv x:Key="conv"/>
      </Page.Resources>
      <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel DataContext="{Binding Source={StaticResource vm}}">
          <TextBlock Text="TextBlock" Margin="5"/>
          <CheckBox Content="Ein / Aus" IsChecked="{Binding Switch, Mode=TwoWay}" Margin="5"/>
          <Button Content="Klick mich" Flyout="{Binding Switch, Converter={StaticResource conv}}"/>
        </StackPanel>
      </Grid>
    </Page>

    ViewModel und Konverter dazu:

    Public Class Page01VM
      Implements INotifyPropertyChanged
    
      Private _swich As Boolean
      Public Property Switch As Boolean
        Get
          Return Me._swich
        End Get
        Set(value As Boolean)
          If Me._swich <> value Then
            Me._swich = value
            OnPropertyChanged()
          End If
        End Set
      End Property
    
    #Region " OnPropertyChanged"
      Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
      Private Sub OnPropertyChanged(<CallerMemberName> Optional propName As String = "")
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
      End Sub
    #End Region
    
    End Class
    
    Public Class Page01Conv
      Implements IValueConverter
    
      Public Function Convert(value As Object, targetType As Type, parameter As Object, language As String) As Object Implements IValueConverter.Convert
        Dim resA = App.Current.Resources("Page01FlyoutA")
        Dim resB = App.Current.Resources("Page01FlyoutB")
        Return If(CType(value, Boolean), resB, resA)
      End Function
    
      Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, language As String) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
      End Function
    End Class


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Freitag, 23. Oktober 2015 07:35
  • Hi Peter

    dein Beispiel sieht suuper aus. Wochenende steht vor der Tür.

    Viele Grüsse

    Bernd Geiger

    Freitag, 23. Oktober 2015 20:49
  • Hi Peter

    Hab gemerkt dass das Beispiel in VB geschrieben ist. Programmiere aber in C#. Sorry hab ich nicht mitgeteilt. Konnte alles nachvollziehen (Der Boolean im VM wird meinem Converter richtig übergeben, die If Verzweigung im Converter funktioniert, also ob PrgMode J/N). Jetzt fehlt mir nur noch der richtige Rückgabewert als StaticResource, die ich nicht in der App.XML definiere, sondern in der aktiven Page(Page.Resources), die als Frame, zur Laufzeit, in die MainPage eingefügt wird. Also mein Problem zur Zeit, dem Converter den richtigen Rückgabewert zu geben. Mein XML Auruf (

    Flyout

    ="{BindingPrgMode,Converter={StaticResourcebooleanToFlyoutConverter}}"). Zum Verständniss meine zwei Converter liegen als eigene Klassendateien in meinem VM Model

    Flyout

    ="{BindingPrgMode,Converter={StaticResourcebooleanToFlyoutConverter}}"



























































































































































































































































































    Freitag, 23. Oktober 2015 23:40
  • Hi Bernd,
    der Konverter befindet sich innerhalb der Anwendung und kann deshalb problemlos auf die Ressourcen der Anwendung zugreifen (auf die Flyouts). Bei der Nutzung des Konverters in den unterschiedlichen Pages usw. weiß der Konverter nicht, wo er genutzt wird und kann deshalb auch nicht auf die Ressourcen in diesen Elementen zugreifen.

    Wenn Du das aber in dieser Art benötigst, dann musst Du in geeigneter Form dem Konverter einen Verweis übergeben, mit welchem er die Ressourcen holen kann. Wenn der Verweis nur auf die Page übergeben wird, müssen die Flyouts einheitliche Namen haben bzw. der Konverter über einen komplizierten switch-Mechanismus mit Fallback bei Fehlen von Ressourcen verfügen. Ein Verweis auf die Seite kann im CodeBehind übergeben werden (über eine zusätzliche Methode im Konverter) oder auch über ein angehängtes Verhalten (attached behavior). Eine andere Alternative wäre ein MultiValue-Konverter, dem die Flyout-Ressourcen mitgegeben werden. Das alles ist aber recht umständlich. Besser ist es (fehlertoleranter), wenn sich Ressourcen und Konverter auf der gleichen Ebene befinden (in der Application).


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Samstag, 24. Oktober 2015 05:37
  • Hi Peter

    du sollst mich nicht gleich so demotivieren, im Detail betrachtet hab ich einfach nur ein Butten, dem ich das Flyout A oder B zuweisen möchte. Der Button ist auch eindeutig deklariert (Name "Kg1" durchlaufend nummeriert. Im <Tag> der Buttons habe ich auch die fortlaufende Zahl hinterlegt. Brauche ich um das richtige Item in meiner ObservableCollection zu selektieren. Möchte jetzt eigentlich nur programmgesteuert, abhängig meinem Boolean, Flyout A oder B aufrufen. Die Converter Methode interessiert mich sehr, aber es wird auch sicherlich eine CodeBehind Methode geben die, die Methode (Flyout = "{StaticResource EingabeFlyOut}"), auf Flyout = "{StaticResource PrgEingabeFlyOut}", wechselt (wenn Converter zu kompliziert ist). Es gibt auch für jeden Button dasselbe Click Event welches mir den dazugehörigen <Tag> ausliest und das entsprechende Item aus meiner Collection, in mein SelectedItem kopiert, auf die wiederum in meinem Flyout über Binding verwiesen wird. Alles außer dem Flyout Wechsel funktioniert. Hab jetzt viel geschrieben aber ich glaube mein Problem jetzt genau beschrieben zu haben: (Flyout A oder B in Abhängigkeit von meinem Boolen) zu wechseln (am liebsten mit einem Converter).

    Mein MVVM Konzept ist (wie Windows 8.1 empfohlen hat) 

    die gelben laufen, den BooleanToFlyoutConverter würde ich gern zum laufen bringen

    Viele Grüsse

    Bernd Geiger 

    Samstag, 24. Oktober 2015 14:39
  • Hi Bernd,
    ich will Dich nicht demotivieren.

    Das Problem des Konverters besteht darin, dass er eine Instanz eines Flyouts in Abhängigkeit eines Wertes liefern muss. Der Konverter kennt nicht die Page, in welcher er genutzt wird. Deshalb kann er auch nicht ein Flyout auswählen, welches in den Ressourcen der Page deklariert ist. Der Konverter befindet sich jedoch in der Application und kann deshalb ein Flyout auswählen, welches sich in der Application befindet (im App.xaml). Wenn der Konverter aber unbedingt ein Flyout auswählen soll, welches in der Page deklariert ist, muss der Konverter eine Information bekommen, um auf die Flyouts zugreifen zu können (Flyouts als Parameter bzw. Bindung oder Verweis auf die Page).

    Da bei der Nutzung von MVVM der ViewModel weder auf "Name", noch auf "Tag" zugreifen kann, da er das Objekt nicht kennt, benötigst Du kein "Name" und auch kein "Tag". Beim Button kann man eine ICommand-Eigenschaft im ViewModel binden und zusätzlich das Element aus der Collection. Damit steht im Command-Ereignis das Element zur Verfügung.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert GeigerBernd Samstag, 24. Oktober 2015 21:08
    • Tag als Antwort aufgehoben GeigerBernd Montag, 26. Oktober 2015 21:17
    • Als Antwort markiert GeigerBernd Montag, 26. Oktober 2015 21:17
    Samstag, 24. Oktober 2015 19:15
  • Hi Peter

    habe für mich eine brauchbare Lösung gefunden. Im Button_Click Event, welches auch den Datensatz Selektiert, selektiere ich auch das passende Flyout, entsprechend meiner Boolean Variable.

    Viele Grüsse

    Bernd Geiger

    Samstag, 24. Oktober 2015 21:07
  • Hi Bernd,
    mit MVVM geht das auch recht einfach. Hier mal eine Demo dazu in C#.NET:

    Oberflächen-XAML:

    <Page
        x:Class="BlankApp01CS.Page01"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01CS"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
      <Page.Resources>
        <local:Page01Conv x:Key="conv"/>
        <DataTemplate x:Key="Page01ListViewTemplate">
          <StackPanel Orientation="Horizontal" Margin="10,0,0,0">
            <Button Content="Klick Flyout" Flyout="{Binding Switch, Converter={StaticResource conv}}" />
            <TextBlock Text="{Binding Info1}" Margin="5"/>
            <TextBlock Text="{Binding Info2}" Margin="5"/>
          </StackPanel>
        </DataTemplate>
        <local:Page01VM x:Key="vm"/>
      </Page.Resources>
      <Grid DataContext="{Binding Source={StaticResource vm}}"
            Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{Binding View}" 
                  ItemTemplate="{StaticResource Page01ListViewTemplate}"/>
      </Grid>
    </Page>

    Dazu die Flyouts im App.xaml:

    <Application
        x:Class="BlankApp01CS.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:BlankApp01CS">
      <Application.Resources>
        <Flyout x:Key="Page01FlyoutA">
          <Grid Background="Red">
            <StackPanel Margin="10">
              <TextBox Text="{Binding Info1, Mode=TwoWay}"/>
              <TextBox Text="{Binding Info2, Mode=TwoWay}"/>
            </StackPanel>
          </Grid>
        </Flyout>
        <Flyout x:Key="Page01FlyoutB">
          <Grid Background="Green">
            <StackPanel Margin="10">
              <TextBox Text="{Binding Info1, Mode=TwoWay}"/>
              <TextBox Text="{Binding Info2, Mode=TwoWay}"/>
            </StackPanel>
          </Grid>
        </Flyout>
      </Application.Resources>
    </Application>

    Und dann noch der ViewModel, Daten-Klasse und Konverter:

    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using Windows.UI.Xaml.Data;
    
    namespace BlankApp01CS
    {
      class Page01VM
      {
        CollectionViewSource cvs;
        ObservableCollection<Page01Data> col;
        Random rnd = new Random();
    
        public ICollectionView View
        {
          get
          {
            if (cvs == null)
            {
              col = new ObservableCollection<Page01Data>();
              for (int i = 1; i < 10; i++)
              {
                col.Add(new Page01Data()
                {
                  Switch = (rnd.NextDouble() > .5),
                  Info1 = string.Format("Datensatz {0}", i),
                  Info2 = string.Format("Wert {0}", rnd.Next(1, 100))});
              }
              cvs = new CollectionViewSource();
              cvs.Source = col;
            }
            return cvs.View;
          }
        }
      }
    
      public class Page01Data : INotifyPropertyChanged
      {
        public bool Switch { get; set; }
    
        private string _info1;
        public string Info1
        {
          get
          {
            return this._info1;
          }
          set
          {
            if (this._info1 != value)
            {
              this._info1 = value;
              OnPropertyChanged();
            }
          }
        }
    
        private string _info2;
        public string Info2
        {
          get
          {
            return this._info2;
          }
          set
          {
            if (this._info2 != value)
            {
              this._info2 = value;
              OnPropertyChanged();
            }
          }
        }
    
        #region OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "")
        {
          if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
        #endregion
      }
    
      public class Page01Conv : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
          var resA = App.Current.Resources["Page01FlyoutA"];
          var resB = App.Current.Resources["Page01FlyoutB"];
          return ((bool)value) ? resB : resA;
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
          throw new NotImplementedException();
        }
      }
    }


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    • Als Antwort markiert GeigerBernd Montag, 26. Oktober 2015 21:19
    Sonntag, 25. Oktober 2015 06:55