WPF – associare una casella di riepilogo a un elenco<string> – che cosa sto facendo di sbagliato?

Sto cercando di fare qualcosa di molto di base qui, qualcosa che non avrei mai creduto che mi dia tanti problemi. Ho una proprietà pubblica nella mia classe Finestra principale chiamato ItemList che è di tipo List<string>. Aggiungo a questa lista per tutta la durata del programma, e vorrei il controllo ListBox ho sul mio modulo per aggiornare automaticamente quando si aggiungono nuovi elementi alla ItemList proprietà.

Finora, ho il seguente codice XAML:

<Window x:Class="ElserBackupGUI.Main"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Backup Profile Editor [New Profile]" Height="480" Width="640">
    <DockPanel>
        <Menu DockPanel.Dock="Top">
            <MenuItem Header="File">
                <MenuItem Header="Open"/>
            </MenuItem>
        </Menu>
        <StackPanel Orientation="Vertical" DockPanel.Dock="Top" Margin="10 10 10 3">
            <TextBlock>Items to backup:</TextBlock>
        </StackPanel>
        <DockPanel DockPanel.Dock="Bottom" Margin="10 0 10 10">
            <StackPanel Orientation="Horizontal">
                <Button Name="AddDirectoryButton" Height="22.725" Width="120" Margin="0 0 6 0" Click="AddDirectoryButton_Click">Add Directory...</Button>
                <Button Name="AddFileButton" Height="22.725" Width="90" Margin="0 0 6 0" Click="AddFileButton_Click">Add File...</Button>
                <Button Name="RemoveDirectoriesButton" Height="22.725" Width="75.447" Margin="0 0 6 0">Remove</Button>
            </StackPanel>
        </DockPanel>
        <ListBox Name="SelectedItems" Margin="10 0 10 10" ItemsSource="{Binding Path=ItemList}"/>
    </DockPanel>
</Window>

Il relativo codice-dietro di codice simile a:

public partial class Main : Window
{
    private string _lastFolder = string.Empty;
    private ObservableCollection<string> _itemList = new ObservableCollection<string>();

    public ObservableCollection<string> ItemList {
        get { return _itemList ?? (_itemList = new ObservableCollection<string>()); }
        set { _itemList = value; }
    }

    public Main()
    {
        InitializeComponent();
        ItemList.Add("test item");
        DataContext = this;
    }

    private void AddDirectoryButton_Click(object sender, RoutedEventArgs e)
    {
        FolderBrowserDialog dialog = new FolderBrowserDialog();
        if (!string.IsNullOrEmpty(_lastFolder))
            dialog.SelectedPath = _lastFolder;

        if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            _lastFolder = dialog.SelectedPath;
            ItemList.Add(dialog.SelectedPath);
        }
    }

    private void AddFileButton_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dialog = new OpenFileDialog();
        if (!string.IsNullOrEmpty(_lastFolder))
            dialog.InitialDirectory = _lastFolder;

        if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            _lastFolder = System.IO.Path.GetDirectoryName(dialog.FileName);
            SelectedItems.ItemsSource = null;
            ItemList.Add(dialog.FileName);
        }
    }
}

Io sono relativamente nuovo per WPF e la maggior parte dei tutorial sembrare troppo complicato per un semplice problema. Mi sembra di non arrivare ovunque qui – che cosa mi manca?

InformationsquelleAutor Chris | 2009-09-28

 

2 Replies
  1. 8

    Si dovrebbe usare BindingList<T> o ObservableCollection<T> invece di List<T>.

    Il problema è che, per associazione a funzionare nel modo desiderato, è necessario implementare INotifyCollectionChanged o IBindingList. List<T> non supporta questa.


    Edit:

    Dopo aver esaminato le modifiche, c’è ancora un problema.

    In AddFileButton_Click gestore di eventi, rimuovere la riga seguente:

    SelectedItems.ItemsSource = null;

    Esplicitamente la rimozione di associazione, e causando la lista deselezionare la casella. Se si rimuove, il codice dovrebbe funzionare così com’è.

    Tuttavia, consiglia di cambiare la vostra collezione di definizione e di costruttore a qualcosa di più come:

        //No need for the null checking every time, or public setter.  They just cause issues
        public ObservableCollection<string> ItemList
        {
            get;
            private set;
        }
    
        //Add construction here, now that we're using an auto-prop
        public Main()
        {
            this.ItemList = new ObservableCollection<string>();
            InitializeComponent();
            ItemList.Add("test item");
            DataContext = this;
        }
    • utilizzare ObservableCollection piuttosto che BindingList, poiché la sua specificamente progettato per associazione di WPF scenari
    • Cito entrambi, e credo che sia di fornire vantaggi. Io di solito d’accordo e raccomandare ObservableCollection, ma se la tua collezione può essere utilizzato da non WPF apps, così, BindingList in grado di fornire vantaggi.
    • Ho provato a cambiare Lista<string> per ObservableCollection<string> e non è cambiato nulla. Ha funzionato bene, ma l’aggiunta di elementi alla raccolta non ha aggiornato il controllo listbox
    • Prendere il dep. proprietà identificatore, come pure – in realtà non è collegato alla proprietà in modo corretto, in modo che tu sei “associazione” sbagliato raccolta. Se si utilizza ObservableCollection, è possibile associare direttamente senza il DP.
    • Ancora nessuna dadi. Sto iniziando a chiedermi se non ho qualcosa di sbagliato da qualche parte.
    • È l’elenco mostrando a tutti? Se è così, mi consiglia di modificare la tua domanda ed aggiungere la vostra “corrente” del codice (con ObservableCollection<T> e non DP), compreso il codice XAML. Possiamo dare un’occhiata, e probabilmente a capire. (È difficile vedere cosa c’è di sbagliato, dal momento che non stiamo guardando l’attuale versione).
    • Se inizializzo la collezione con alcuni dati di prova, mostra, ma il minuto mi chiama una funzione che cerca di aggiungere qualcosa per la raccolta, il controllo listbox viene cancellato. Ogni pensiero?
    • Ho aggiornato il mio codice in OP per il codice corrente.
    • Un’idea del perché la listbox è svuotato quando mi aggiungi 1 o più elementi all’insieme?
    • Chris: ho appena aggiornato la mia risposta: ti basterà commentare/eliminare una riga, e il tuo attuale lavoro. Ho aggiunto altre note, troppo, però.
    • DOH! Ho completamente perso quella linea. Che era da prima, quando ero risoluzione dei problemi e assolutamente non dovrebbe essere lì. Rimozione di una linea fissa. Grazie!

  2. 1

    Non mi piace questo getter… personalmente. Guarda cospicua.

    get { return _itemList ?? (_itemList = new ObservableCollection<string>()); }

    Sei già inizializzazione del _itemList nella dichiarazione. Se hai bisogno di fare il doppio gioco per sentirsi al sicuro, è il costruttore.

    • Sono d’accordo – ho detto che nella mia ultima modifica, come bene. Non causando il suo problema, però, non è solo aiutare nulla.
    • Sì il codice aggiuntivo è stato prima che mi è stato inizializzazione della lista nella dichiarazione. Ho rimosso il codice ridondante ora.

Lascia un commento