Frage

Ich bin ein (relativ) erfahrener Kakao-/Objektiv-C-Codierer und unterrichte mir C# und das WPF-Framework.

In Kakao, wenn sie eine bevölkern NSTableView, Es ist relativ einfach, der Ansicht einen Delegierten und eine Datenquelle zuzuweisen. Diese Delegierten-/Datenquellenmethoden werden dann verwendet, um die Tabelle zu füllen und ihr Verhalten zu bestimmen.

Ich stelle eine einfache Anwendung zusammen, die eine Liste von Objekten enthält, und rufen Sie sie an Dog Objekte, die jeweils a haben public string name. Dies ist der Rückgabewert von Dog.ToString().

Die Objekte werden in a angezeigt ListBox, und ich möchte diese Ansicht mit einem ähnlichen Muster wie Kakaos von Kakao bevölkern NSTableViewDataSource. Es scheint derzeit zu funktionieren, wenn es darum geht:

public partial class MainWindow : Window, IEnumerable<Dog>
    {
        public Pound pound = new Pound();

        public MainWindow()
        {
            InitializeComponent();

            Dog fido = new Dog();
            fido.name = "Fido";
            pound.AddDog(fido);

            listBox1.ItemsSource = this;

            Dog spot = new Dog();
            spot.name = "Spot";
            pound.AddDog(spot);
        }

        public IEnumerator<Dog> GetEnumerator()
        {
            return currentContext.subjects.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

Aber ich frage mich, wie Korrekt das ist. Ich habe buchstäblich Visual Studio für weniger als eine Stunde installiert, daher kann man mit Sicherheit sagen, dass ich keine Ahnung habe, was ich tue.

  1. Ist das das richtige Muster?
  2. Hinzufügen des zweiten Elements zur Liste (spot) scheint das zu aktualisieren ListBox Richtig, aber ich frage mich, was die Updates auslöst.
  3. Was passiert, wenn ich die aktualisiere Pound Auf einem Hintergrund Thread?
  4. Wie kann ich das manuell fragen ListBox sich selbst aktualisieren? (Muss ich überhaupt?)

Eine Änderung Dass ich weiß, dass ich machen muss IEnumerable<Dog> Implementierung in eine eigene Klasse wie DogListItemsSource, aber ich möchte sicherstellen, dass ich einen soliden Ansatz habe, bevor ich ihn poliere.

Fühlen Sie sich frei Um in Kommentaren auf andere Punkte zu hinweisen, die ich ansprechen oder berücksichtigen sollte, groß oder klein. Ich möchte das zum ersten Mal richtig lernen.

War es hilfreich?

Lösung

Mein Vorschlag wäre, neben Ihrem Fenster eine Klasse zu erstellen, die für die Bereitstellung der Daten für Ihre verantwortlich wäre ListBox. Ein gemeinsamer Ansatz ist WPF heißt MVVM, was wie jedes Muster viele Implementierungen hat.

Die Grundlagen sind jedes Modell (z. B. Pound und Dog) würde ein Ansichtsmodell für die Präsentation des Modells auf eine Weise verantwortlich sein, die leicht mit der Benutzeroberfläche interagieren kann.

Um Ihnen den Einstieg zu erleichtern, bietet WPF eine hervorragende Klasse. ObservableCollection<T>, Das ist eine Sammlung, die ein Ereignis "Hey, ich habe geändert" abfeuert, wenn jemand hinzugefügt, bewegt oder entfernt wird.

Im Folgenden finden Sie ein Beispiel, das Ihnen nicht beabsichtigt, Ihnen MVVM beizubringen, und es verwendet auch keinen Rahmen für MVVM. Wenn Sie jedoch einige Haltepunkte festlegen und damit spielen, werden Sie sich über Bindungen, Befehle, InotifyPropertychanged und die Beobachtungspunkte kennenlernen. All dies spielt eine große Rolle in der WPF -Anwendungsentwicklung.

Beginnend in der MainWindow, Sie können Ihre festlegen DataContext zu einem Ansichtsmodell:

public class MainWindow : Window
{
     // ...
     public MainWindow()
     {
         // Assigning to the DataContext is important
         // as all of the UIElement bindings inside the UI
         // will be a part of this hierarchy
         this.DataContext = new PoundViewModel();

         this.InitializeComponent();
     }
}

Bei dem die PoundViewModel verwaltet eine Sammlung von DogViewModel Objekte:

public class PoundViewModel
{
    // No WPF application is complete without at least 1 ObservableCollection
    public ObservableCollection<DogViewModel> Dogs
    {
        get;
        private set;
    }

    // Commands play a large role in WPF as a means of 
    // transmitting "actions" from UI elements
    public ICommand AddDogCommand
    {
        get;
        private set;
    }

    public PoundViewModel()
    {
        this.Dogs = new ObservableCollection<DogViewModel>();

        // The Command takes a string parameter which will be provided
        // by the UI. The first method is what happens when the command
        // is executed. The second method is what is queried to find out
        // if the command should be executed
        this.AddDogCommand = new DelegateCommand<string>(
            name => this.Dogs.Add(new DogViewModel { Name = name }),
            name => !String.IsNullOrWhitespace(name)
        );
    }
}

Und in deinem xaml (Stellen Sie sicher xmlns:local Damit XAML Ihre Ansichtsmodelle verwenden kann):

<!-- <Window ...
             xmlns:local="clr-namespace:YourNameSpace" -->
<!-- Binding the ItemsSource to Dogs, will use the Dogs property
  -- On your DataContext, which is currently a PoundViewModel
  -->
<ListBox x:Name="listBox1"
         ItemsSource="{Binding Dogs}">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type local:DogViewModel}">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5">
                <TextBox Text="{Binding Name}" />
            </Border>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>
<GroupBox Header="New Dog">
    <StackPanel>
        <Label>Name:</Label>
        <TextBox x:Name="NewDog" />

        <!-- Commands are another big part of WPF -->
        <Button Content="Add"
                Command="{Binding AddDogCommand}"
                CommandParameter="{Binding Text, ElementName=NewDog}" />
    </StackPanel>
</GroupBox>

Natürlich würden Sie eine brauchen DogViewModel:

public class DogViewModel : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return this.name; }
        set
        {
            this.name = value;

            // Needed to alert WPF to a change in the data
            // which will then update the UI
            this.RaisePropertyChanged("Name");
        }
    }

    public event PropertyChangedHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Schließlich benötigen Sie eine Implementierung von DelegateCommand<T>:

public class DelegateCommand<T> : ICommand
{
    private readonly Action<T> execute;
    private readonly Func<T, bool> canExecute;
    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<T> execute, Func<T, bool> canExecute)
    {
        if (execute == null) throw new ArgumentNullException("execute");
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(T parameter)
    {
        return this.canExecute != null && this.canExecute(parameter); 
    }

    bool ICommand.CanExecute(object parameter)
    {
        return this.CanExecute((T)parameter);
    }

    public void Execute(T parameter)
    {
        this.execute(parameter);
    }

    bool ICommand.Execute(object parameter)
    {
        return this.Execute((T)parameter);
    }
}

Diese Antwort hat keineswegs dazu führen, dass Sie immersive, voll gebundene WPF -Benutzeroberfläche aufschlagen, aber hoffentlich gibt es Ihnen ein Gefühl dafür, wie die Benutzeroberfläche mit Ihrem Code interagieren kann!

Andere Tipps

  1. In WPF haben Sie normalerweise nur eine Sammlung als itemsSource und Datenvorlagen zum Anzeigen des Elements.

  2. Normalerweise aktualisieren diese Steuerelemente nur, wenn die ElementSource -Instanz implementiert wird INotifyCollectionChanged, Vielleicht haben Sie den Artikel vor dem hinzugefügt ListBox abgerufen.

  3. Was ist Pfund? Es sei denn, Pound hat etwas Fadenaffinität als z. B. ObservableCollection tut, das ist kein Problem, wenn dies der Fall ist, müssen Sie verwenden Versand.

  4. ListBox.Items.Refresh() Könnte das tun, aber normalerweise verwenden Sie nur eine Sammlung mit Benachrichtigungen.

WPF verwendet stark Datenbindung. Wenn Sie also das Framework lernen möchten Die jeweilige Übersicht (zusammen mit all die anderen) könnte von Interesse sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top