none
Statusänderungen der ListViewItems speichern RRS feed

  • Frage

  • Hallo,

    Ich habe eine ListView, die mir die Dateien eines Verzeichnisses anzeigt. Der User soll dann ein oder mehrere Dateien auswählen können, die dann per Botton geöffnet werden sollen. Um die Liste aller Dateinamen und die Dateinamen, die ausgewählt worden sind, in einer statischen Klasse zu speichern, habe ich in einer eigenen Klasse 2 public Variablen Dateinamen und Ausgewaehlt definiert. Mittels Dateibindung wird die Liste der Dateinamen in meiner Klasse als String-Liste (Dateinamen) auch gespeichert. Klappt soweit auch. Jetzt will ich noch die ausgewählten ListviewItems (selectedItems) in meiner boolschen Variable speichern. Ich dachte erst an Trigger, um das zu machen. Denke jetzt aber, dass dafür die Trigger nicht gedacht sind, sondern dass man das über eine (dynamische) Bindungsdefinition machen muss. Das Abspeichern der selectedItems in meiner boolschen Variable muss ja dynamisch und nicht statisch wie mit den Dateinamen erfolgen. Wie kann ich das erreichen?

    <ListView x:Name="listView1"
    Height="100" Width="297" Margin="63,118,0,0"
    VerticalAlignment="Top" HorizontalAlignment="Left"
    SelectionChanged="listView1_SelectionChanged"> <ListView.ItemTemplate> <DataTemplate> <TextBlock x:Name="TxtBlock2" Text="{Binding Path=DateiName}" /> </DataTemplate> </ListView.ItemTemplate> </ListView>

    Hier die Definition in meiner Klasse:

    public class FileObject 
    { 
        private string dateiName; 
        private bool ausgewaehlt;
     
        public FileObject(string dateiName, bool ausgewaehlt)
        { 
            this.dateiName = dateiName; 
            this.ausgewaehlt = ausgewaehlt;
        }
     
        public string DateiName
        { 
            get{ return dateiName; } 
            set{ dateiName = value;}
        }
     
        public bool Ausgewaehlt
        { 
            get{ return ausgewaehlt; } 
            set{ ausgewaehlt = value;}
        }
    }
    Gruß Andreas

    Sonntag, 16. August 2015 12:41

Antworten

  • Hallo Andreas,

    jetzt weiß ich was du vor hast :)

    Der Trick besteht darin per ItemContainerStyle die IsSelected-Eigenschaft zu binden:

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsSelected" Value="{Binding Ausgewaehlt, Mode=TwoWay}"/>
        </Style>
    </ListView.ItemContainerStyle>
    Dieser Style wird auf jedes ListViewItem angewendet, das in der dazugehörigen ListBox ist. Entsprechend wird jedem Item die IsSelected-Eigenshcaft entsprechend der Ausgewaehlt-Eigenschaft zugewiesen.

    Noch 2 andere Hinweise:
    Auf Deutsch programmieren empfinde ich zwar nach wie vor als seltsam, ist aber machbar. Wenn man das macht, sollte man es aber auch konsequent durchziehen und die Klasse DateiObjekt nennen. Schöner fände ich es alles auf Englisch zu machen, so passt es mehr zum Framework-Code.

    Damit die Datenbindungen wirklich in beide Richtungen funktionieren, musst du noch INotifyPropertyChanged implementieren, sonst aktualisiert sich die GUI nicht richtig. Diese Schnittstelle informiert die GUI über die Änderung einer Eigenschaft, sofern du das PropertyChanged-Event in den Settern der Eigenschaften auslöst.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert AndreasM2000 Sonntag, 16. August 2015 14:52
    Sonntag, 16. August 2015 14:04
    Moderator

Alle Antworten

  • Hallo Andreas,

    jetzt weiß ich was du vor hast :)

    Der Trick besteht darin per ItemContainerStyle die IsSelected-Eigenschaft zu binden:

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="IsSelected" Value="{Binding Ausgewaehlt, Mode=TwoWay}"/>
        </Style>
    </ListView.ItemContainerStyle>
    Dieser Style wird auf jedes ListViewItem angewendet, das in der dazugehörigen ListBox ist. Entsprechend wird jedem Item die IsSelected-Eigenshcaft entsprechend der Ausgewaehlt-Eigenschaft zugewiesen.

    Noch 2 andere Hinweise:
    Auf Deutsch programmieren empfinde ich zwar nach wie vor als seltsam, ist aber machbar. Wenn man das macht, sollte man es aber auch konsequent durchziehen und die Klasse DateiObjekt nennen. Schöner fände ich es alles auf Englisch zu machen, so passt es mehr zum Framework-Code.

    Damit die Datenbindungen wirklich in beide Richtungen funktionieren, musst du noch INotifyPropertyChanged implementieren, sonst aktualisiert sich die GUI nicht richtig. Diese Schnittstelle informiert die GUI über die Änderung einer Eigenschaft, sofern du das PropertyChanged-Event in den Settern der Eigenschaften auslöst.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert AndreasM2000 Sonntag, 16. August 2015 14:52
    Sonntag, 16. August 2015 14:04
    Moderator
  • Hi Andreas,
    eine andere Variante wäre die Einbindung einer Checkbox in ein ListViewItem und Bindung dieser Checkbox. Dazu eine keline Demo:

    XAML:

    <Window x:Class="WpfApplication1CS.Window03"
            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:WpfApplication1CS"
            mc:Ignorable="d"
            Title="Window03" Height="300" Width="300">
      <Window.Resources>
        <local:Window03VM x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{Binding Source={StaticResource vm}}">
        <Grid.RowDefinitions>
          <RowDefinition/>
          <RowDefinition Height="auto"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding View}">
          <ListView.View>
            <GridView>
              <GridViewColumn Header="Auswahl">
                <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <CheckBox IsChecked="{Binding Select}" />
                  </DataTemplate>
                </GridViewColumn.CellTemplate>
              </GridViewColumn>
              <GridViewColumn Header="Inhalt" Width="100">
                <GridViewColumn.CellTemplate>
                  <DataTemplate>
                    <TextBlock Text="{Binding Info}"/>
                  </DataTemplate>
                </GridViewColumn.CellTemplate>
              </GridViewColumn>
            </GridView>
          </ListView.View>
        </ListView>
        <Button Grid.Row="1" Content="Anzeige" Command="{Binding Cmd}" Margin="10"/>
        <TextBlock Grid.Row="2" Text="{Binding Ausgewaehlt}"/>
      </Grid>
    </Window>

    Und der ViewModel dazu:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Linq;
    
    namespace WpfApplication1CS
    {
      class Window03VM : INotifyPropertyChanged
      {
        ObservableCollection<Window03Data> Liste;
        CollectionViewSource cvs;
    
        public ICollectionView View
        {
          get
          {
            if (Liste == null)
            {
              Liste = new ObservableCollection<Window03Data>();
              cvs = new CollectionViewSource();
              for (int i = 1; i < 10; i++)
              {
                Liste.Add(new Window03Data() { ID = i, Info = string.Format("Zeile {0}", i) });
              }
              cvs.Source = Liste;
            }
            return cvs.View;
          }
        }
    
        public ICommand Cmd
        {
          get
          {
            return new RelayCommand(CmdExec);
          }
        }
    
        private void CmdExec(object obj)
        {
          Ausgewaehlt = "Selektierte Zeilen: ";
          foreach (var item in from itm in Liste where itm.Select select itm)
          {
            Ausgewaehlt += item.Info + "; ";
          }
        }
    
        private string _ausgewaehlt;
        public string Ausgewaehlt
        {
          get
          {
            return this._ausgewaehlt;
          }
          set
          {
            if (this._ausgewaehlt != value)
            {
              this._ausgewaehlt = 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 Window03Data
        {
          public int ID { get; set; }
          public string Info { get; set; }
          public bool Select { get; set; }
        }
      }
    }


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

    Sonntag, 16. August 2015 14:36
  • Hallo Tom,

    ja, danach habe ich gesucht. Vielen Dank für den Trick. Klappt jetzt alles.

    Ich war inzwischen schon auf einem anderen Weg:

    privatevoidlistView1_SelectionChanged(objectsender, SelectionChangedEventArgse)

    Habe das aber nicht mehr ganz zu Ende gebracht. Sollte so aber auch funktionieren. Die selektierten Einträge hatte ich schon in der Hand. Über die XAML-Lösung sieht es aber vielleicht auch lesbarer aus.

    ja, Du hast Recht. Ich bin in der Namensgebung nicht ganz konsequent. Ich verwende deutsche Namen, um leichter den Unterschied zwischen meinem Code und vordefinierten C#-Bezeichnern zu erkennen. Aber das mache ich wahrscheinlich auch nur Anfang, solange ich meinem eigenen Code nicht immer vollständig traue und dort immer die Fehler suche.

    Einen EventHandler hatte ich schon eingebaut, sodass auch alles sofort geklappt hat.

    Gruß Andreas 

    Sonntag, 16. August 2015 14:51