none
Event eines Templates RRS feed

  • Frage

  • Hallo Leute,
    ich habe zB. ein Cell-Template, welches ein Event enthält.
    Wie ist es möglich, dass ich dieses Event konsumieren kann?

    Vielen Dank im Voraus


    Christian Tauschek

    Dienstag, 12. Februar 2019 12:15

Antworten

  • Hi Christian,
    Du postest nicht im WPF-Forum (unvollständigen für Testzwecke) C#-Code im VB.NET-Forum. Wie soll man das werten?

    Mit SetBinding kannst Du als Datenquelle für die CommandProperty eine ICommand-Eigenschaft in der CMyListViewBestellungen-Klasse setzen. Damit kommt dann das Ereignis in der Eigenschaft an, die über ICommand ausgeführt wird (z.B. ein Execute der Instanz der RelayCommand-Klasse). Die Clicked-Ereignismethode brauchst Du dann nicht.

    Ich würde aber das Design vollständig im XAML definieren (ohne Deinen Code für das DataTemplate).


    Hier mal eine Demo für WPF:

    XAML:

    <Window x:Class="WpfApp1.Window92"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window92" Height="450" Width="800">
      <Window.Resources>
        <local:Window92VM x:Key="vm"/>
        <DataTemplate x:Key="itmp">
          <Button Content="Klick mich" 
                  Command="{Binding Source={StaticResource vm}, Path=Cmd}"
                  CommandParameter="{Binding ID}"/>
        </DataTemplate>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <ListView ItemsSource="{Binding View}" ItemTemplate="{StaticResource itmp}"/>
      </Grid>
    </Window>

    Und dazu der ViewModel nicht in VB.NET, sondern in C#.NET:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      public class Window92VM : INotifyPropertyChanged
      {
        /// <summary>
        /// Konstruktor, in welchem die Demodaten geladen werden
        /// </summary>
        public Window92VM()
        {
          // Liste mit Daten laden
          ObservableCollection<Window92Data> col = new ObservableCollection<Window92Data>();
          for (int i = 1; i < 10; i++) col.Add(new Window92Data() { ID = i, Info = $"Zeile {i}" });
          cvs.Source = col; // der Sichtquelle zuweisen
        }
    
        /// <summary>
        /// Sichtquelle der Liste mit Daten
        /// </summary>
        private CollectionViewSource cvs = new CollectionViewSource();
    
        /// <summary>
        /// Eigenschaft für Anzeige der Daten
        /// </summary>
        public ICollectionView View { get { return cvs.View; } }
        
        /// <summary>
        /// Befehlsbindung
        /// </summary>
        public ICommand Cmd { get { return new RelayCommand((obj) => MessageBox.Show($"Meldung von {obj}")); } }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
      }
      public class Window92Data
      {
        public int ID { get; set; }
        public string Info { get; set; }
      }
    }
    


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



    Dienstag, 12. Februar 2019 17:43
  • Hi Christian,
    ich habe das mal in Xamarin getestet. Da es kein ICollectionView gibt, musst Du die ObeservableCollection für die Bindung nutzen.

    XAML:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:App1"
                 x:Class="App1.MainPage">
      <ContentPage.Resources>
        <local:ViewModel x:Key="vm"/>
        <DataTemplate x:Key="itmp">
          <ViewCell>
            <StackLayout Orientation="Horizontal">
              <Label Text="{Binding Info}" HorizontalOptions="Start" />
              <Button Text="Klick mich" 
                  Command="{Binding Source={StaticResource vm}, Path=Cmd}"
                  CommandParameter="{Binding ID}"/>
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ContentPage.Resources>
      <Grid BindingContext="{x:StaticResource vm}">
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding View}" ItemTemplate="{x:StaticResource itmp}"/>
        <Label Grid.Row="1" Text="{Binding Status}"/>
      </Grid>
    
    </ContentPage>

    Und dazu der ViewModel:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows.Input;
    
    namespace App1
    {
      class ViewModel : INotifyPropertyChanged
      {
        /// <summary>
        /// Konstruktor, in welchem die Demodaten geladen werden
        /// </summary>
        public ViewModel()
        {
          // Liste mit Daten laden
          col = new ObservableCollection<Data>();
          for (int i = 1; i < 10; i++) col.Add(new Data() { ID = i, Info = $"Zeile {i}" });
        }
    
        private ObservableCollection<Data> col;
    
        /// <summary>
        /// Eigenschaft für Anzeige der Daten
        /// </summary>
        public ObservableCollection<Data> View { get { return col; } }
    
        /// <summary>
        /// Befehlsbindung
        /// </summary>
        public ICommand Cmd { get { return new RelayCommand<int>((i) => Status = $"Meldung von {i}"); } }
    
        private string _status = "<status>";
        public string Status { get { return this._status; } set { this._status = value; OnPropertyChanged(); } }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
      }
      public class Data
      {
        public int ID { get; set; }
        public string Info { get; set; }
      }
    }

    Beim Klick auf einen Button im Element im ListView wird unten in der Label die ID des angeklickten Elementes angezeigt.

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


    Sonntag, 17. Februar 2019 10:01

Alle Antworten

  • Hi Christian,
    Deine Frage ist etwas unklar. Üblicherweise wird das CellTemplate für die Darstellung des Wertes einer gebundenen Eigenschaft genutzt. Der Anwender geht in den Edit-Modus, verändert den Wert und lässt den veränderten Wert in die gebundene Eigenschaft ablegen (z.B. beim Verlassen des Edit-Modus). Und im Setter der Eigenschaft kannst Du diese Aktivität des Anwenders fangen.

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

    Dienstag, 12. Februar 2019 13:20
  • Hallo Peter,
    in der Klasse CMyListViewBestellungen weise ich das DataTemplate vom Typ ListItemBestellungCell zu.
    In der ListItemBestellungCell ist ein Event ButLöschen.Clicked enthalten und es wird auch die
    Funktion 
    ButLöschen_Clicked beim Klicken auf den Button aufgerufen.
    Mein Problem ist jedoch, dass ich dieses Event in der Klasse CMyListViewBestellungen benötige.Wie kann ich das anstellen?
    mfg
    Christian


        class CMyListViewBestellungen : CMyListView
        {
            public CMyListViewBestellungen()
            {
                ItemTemplate = new DataTemplate(typeof(ListItemBestellungCell));
            }
        }
    
        class ListItemBestellungCell : ViewCell
        {
            public ListItemBestellungCell()
            {
                
                CMyImageButton butLöschen = new CMyImageButton { Source = "inaktiv.png", HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Center };
                butLöschen.SetBinding(CMyButton.CommandParameterProperty, new Binding("."));
                butLöschen.Clicked += ButLöschen_Clicked;
    
                StackLayout viewLayoutItem = new StackLayout()
                {
                    Padding = new Thickness(3),
                    Orientation = StackOrientation.Horizontal,
                    Children = { butLöschen }
                };
    
                View = viewLayoutItem;
    
            }
    
            private void ButLöschen_Clicked(object sender, EventArgs e)
            {
                CMyImageButton button = ((CMyImageButton)sender);
                var f = button.CommandParameter;///// Test''''''''
            }


    Christian Tauschek


    Dienstag, 12. Februar 2019 13:35
  • Hi Christian,
    Du postest nicht im WPF-Forum (unvollständigen für Testzwecke) C#-Code im VB.NET-Forum. Wie soll man das werten?

    Mit SetBinding kannst Du als Datenquelle für die CommandProperty eine ICommand-Eigenschaft in der CMyListViewBestellungen-Klasse setzen. Damit kommt dann das Ereignis in der Eigenschaft an, die über ICommand ausgeführt wird (z.B. ein Execute der Instanz der RelayCommand-Klasse). Die Clicked-Ereignismethode brauchst Du dann nicht.

    Ich würde aber das Design vollständig im XAML definieren (ohne Deinen Code für das DataTemplate).


    Hier mal eine Demo für WPF:

    XAML:

    <Window x:Class="WpfApp1.Window92"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="Window92" Height="450" Width="800">
      <Window.Resources>
        <local:Window92VM x:Key="vm"/>
        <DataTemplate x:Key="itmp">
          <Button Content="Klick mich" 
                  Command="{Binding Source={StaticResource vm}, Path=Cmd}"
                  CommandParameter="{Binding ID}"/>
        </DataTemplate>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <ListView ItemsSource="{Binding View}" ItemTemplate="{StaticResource itmp}"/>
      </Grid>
    </Window>

    Und dazu der ViewModel nicht in VB.NET, sondern in C#.NET:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
      public class Window92VM : INotifyPropertyChanged
      {
        /// <summary>
        /// Konstruktor, in welchem die Demodaten geladen werden
        /// </summary>
        public Window92VM()
        {
          // Liste mit Daten laden
          ObservableCollection<Window92Data> col = new ObservableCollection<Window92Data>();
          for (int i = 1; i < 10; i++) col.Add(new Window92Data() { ID = i, Info = $"Zeile {i}" });
          cvs.Source = col; // der Sichtquelle zuweisen
        }
    
        /// <summary>
        /// Sichtquelle der Liste mit Daten
        /// </summary>
        private CollectionViewSource cvs = new CollectionViewSource();
    
        /// <summary>
        /// Eigenschaft für Anzeige der Daten
        /// </summary>
        public ICollectionView View { get { return cvs.View; } }
        
        /// <summary>
        /// Befehlsbindung
        /// </summary>
        public ICommand Cmd { get { return new RelayCommand((obj) => MessageBox.Show($"Meldung von {obj}")); } }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
      }
      public class Window92Data
      {
        public int ID { get; set; }
        public string Info { get; set; }
      }
    }
    


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



    Dienstag, 12. Februar 2019 17:43
  • Hallo Peter,
    ich wollte bei meinem ersten Posting eigentlich keinen Code posten und bislang habe ich immer im VB-Forum Fragen gestellt, weil ich immer gute Antworten - auch von dir - erhalten habe.
    Ich habe das Serverprogramm in VB gemacht und dieses bedient die Abfragen eines Xamarin-Programmes für ein Handy. Deswegen auch C#.
    Mir ist es im Prinzip egal, ob ich eine Antwort in C# oder VB erhalte - ist ja vom Prinzip her das Gleiche.

    Dein Beispiel kann ich leider nicht testen, weil mir in Xamarin System.Windows.Data nicht zur Verfügung steht.

    Bei meinem Beispiel weise ich meiner CMyListViewBestellungen mittels ItemTemplate = new DataTemplate(typeof(ListItemBestellungCell));
    ein Cell-Template zu, das einen Löschen-Button enthält.

    Jedoch schaffe ich es nicht das Click-Event in
    CMyListViewBestellungen zu verarbeiten.
    In der Template-Klasse
    ListItemBestellungCell ist das natürlich schon möglich. Jedoch bringt es mir in dieser Klasse nichts.

    mfg
    Christian Tauschek


    Christian Tauschek


    Freitag, 15. Februar 2019 20:42
  • Hi Christian,
    ich habe das mal in Xamarin getestet. Da es kein ICollectionView gibt, musst Du die ObeservableCollection für die Bindung nutzen.

    XAML:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:App1"
                 x:Class="App1.MainPage">
      <ContentPage.Resources>
        <local:ViewModel x:Key="vm"/>
        <DataTemplate x:Key="itmp">
          <ViewCell>
            <StackLayout Orientation="Horizontal">
              <Label Text="{Binding Info}" HorizontalOptions="Start" />
              <Button Text="Klick mich" 
                  Command="{Binding Source={StaticResource vm}, Path=Cmd}"
                  CommandParameter="{Binding ID}"/>
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ContentPage.Resources>
      <Grid BindingContext="{x:StaticResource vm}">
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding View}" ItemTemplate="{x:StaticResource itmp}"/>
        <Label Grid.Row="1" Text="{Binding Status}"/>
      </Grid>
    
    </ContentPage>

    Und dazu der ViewModel:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows.Input;
    
    namespace App1
    {
      class ViewModel : INotifyPropertyChanged
      {
        /// <summary>
        /// Konstruktor, in welchem die Demodaten geladen werden
        /// </summary>
        public ViewModel()
        {
          // Liste mit Daten laden
          col = new ObservableCollection<Data>();
          for (int i = 1; i < 10; i++) col.Add(new Data() { ID = i, Info = $"Zeile {i}" });
        }
    
        private ObservableCollection<Data> col;
    
        /// <summary>
        /// Eigenschaft für Anzeige der Daten
        /// </summary>
        public ObservableCollection<Data> View { get { return col; } }
    
        /// <summary>
        /// Befehlsbindung
        /// </summary>
        public ICommand Cmd { get { return new RelayCommand<int>((i) => Status = $"Meldung von {i}"); } }
    
        private string _status = "<status>";
        public string Status { get { return this._status; } set { this._status = value; OnPropertyChanged(); } }
    
        #region  OnPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion
      }
      public class Data
      {
        public int ID { get; set; }
        public string Info { get; set; }
      }
    }

    Beim Klick auf einen Button im Element im ListView wird unten in der Label die ID des angeklickten Elementes angezeigt.

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


    Sonntag, 17. Februar 2019 10:01