C# 使用ItemsSource填充WPF列表框-好主意?

C# 使用ItemsSource填充WPF列表框-好主意?,c#,wpf,listbox,ienumerator,C#,Wpf,Listbox,Ienumerator,我是一个(相对)有经验的Cocoa/Objective-C编码器,我在自学C#和WPF框架 在Cocoa中,在填充NSTableView时,将委托和数据源分配给视图相对简单。然后使用这些委托/数据源方法填充表并确定其行为 我正在组装一个简单的应用程序,它有一个对象列表,让我们称它们为Dog对象,每个对象都有一个公共字符串名。这是Dog.ToString()的返回值 这些对象将显示在一个列表框中,我想使用与Cocoa的NSTableViewDataSource类似的模式填充此视图。它目前似乎正在使

我是一个(相对)有经验的Cocoa/Objective-C编码器,我在自学C#和WPF框架

在Cocoa中,在填充
NSTableView
时,将委托和数据源分配给视图相对简单。然后使用这些委托/数据源方法填充表并确定其行为

我正在组装一个简单的应用程序,它有一个对象列表,让我们称它们为
Dog
对象,每个对象都有一个
公共字符串名
。这是
Dog.ToString()
的返回值

这些对象将显示在一个
列表框中
,我想使用与Cocoa的
NSTableViewDataSource
类似的模式填充此视图。它目前似乎正在使用:

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();
        }
    }
public分部类主窗口:窗口,IEnumerable
{
公共英镑=新英镑();
公共主窗口()
{
初始化组件();
狗fido=新狗();
fido.name=“fido”;
庞德·阿多格(fido);
listBox1.ItemsSource=this;
狗斑=新狗();
spot.name=“spot”;
磅。加狗(点);
}
公共IEnumerator GetEnumerator()
{
返回currentContext.subjects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
返回GetEnumerator();
}
}
但我想知道这有多正确。实际上,我安装VisualStudio不到一个小时,所以可以肯定地说我不知道自己在做什么

  • 这是正确的模式吗
  • 将第二项添加到列表(
    spot
    )似乎可以正确地更新
    ListBox
    ,但我想知道是什么触发了更新
  • 如果我在后台线程上更新
    Pound
    ,会发生什么
  • 如何手动要求
    列表框
    进行自我更新?(我需要吗?)
  • 我知道我需要做的一个改变是将
    IEnumerable
    实现重构到自己的类中,比如
    DogListItemsSource
    ,但我想确保在完善它之前有一个可靠的方法

    请随意在评论中指出我应该解决或记住的任何其他要点,无论大小。我想第一次用正确的方法来学习

  • 在WPF中,通常只有一些集合作为ItemsSource并显示该项

  • 通常,这些控件仅在ItemsSource实例实现时更新,可能是您在
    列表框
    检索该项之前添加了该项

  • 英镑是多少?除非Pound有一些线程亲和力,例如,如果您需要使用它,那么这是没有问题的

  • ListBox.Items.Refresh()可以做到这一点,但通常只使用带有通知的集合


  • WPF大量使用数据绑定,因此如果您想了解框架(以及),可能会感兴趣。

    我的建议是在窗口之外创建一个类,负责将数据提供给您的
    列表框。一种常见的方法是调用WPF,它与任何模式一样有许多实现

    基本要求是,每个模型(例如,
    Pound
    Dog
    )都有一个视图模型,负责以易于从UI交互的方式呈现模型

    为了让您开始,WPF提供了一个优秀的类,它是一个集合,每当添加、移动或删除任何人时都会触发“Hey I Changed”事件

    下面的示例并不打算教您MVVM,也不使用任何MVVM框架。但是,如果您设置一些断点并使用它,您将了解绑定、命令、INotifyPropertyChanged和ObservableCollection;所有这些都在WPF应用程序开发中扮演着重要角色

    main窗口开始
    ,可以将
    DataContext
    设置为视图模型:

    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();
         }
    }
    
    其中,
    PoundViewModel
    管理
    DogViewModel
    对象的集合:

    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)
            );
        }
    }
    
    当然,您需要一个
    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));
        }
    }
    
    最后,您需要实现:

    公共类DelegateCommand:ICommand
    {
    私有只读操作执行;
    私有只读功能可执行;
    公共事件处理程序CanExecuteChanged;
    公共DelegateCommand(操作执行,Func canExecute)
    {
    如果(execute==null)抛出新的ArgumentNullException(“execute”);
    this.execute=execute;
    this.canExecute=canExecute;
    }
    公共布尔CanExecute(T参数)
    {
    返回this.canExecute!=null&&this.canExecute(参数);
    }
    bool ICommand.CanExecute(对象参数)
    {
    返回此.CanExecute((T)参数);
    }
    公共void执行(T参数)
    {
    执行(参数);
    }
    bool ICommand.Execute(对象参数)
    {
    返回此.Execute((T)参数);
    }
    }
    

    这个答案决不会让你创造出沉浸式的、完全绑定的WPF UI,但希望它能让你感受到UI是如何与代码交互的

    哎呀,这东西太复杂了!与KVO、MVC和IBOutlets的简单性相去甚远,但也许我仍然需要对其进行热身。:)非常感谢您的解释和定制的示例,在接下来的几天里,我将经常提到它。@craig:是的,它与Obj-C不同,这是肯定的。当然,从WPF到Obj-C/Cocoa,我经历了一段艰难的时光;)MVVM框架的有用链接:或和都是很好的起点。
    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);
        }
    }