简体   繁体   English

使用ObservableCollection绑定到ItemSource的列表框麻烦

[英]Listbox Trouble with Binding to ItemSource using a ObservableCollection

I am having trouble binding to the ItemsSource of a List box control. 我在绑定到列表框控件的ItemsSource时遇到麻烦。 I would like to be able to add text lines to the List box when the user preforms certain actions. 当用户执行某些操作时,我希望能够在“列表”框中添加文本行。

The SystemControls.xmal Code: SystemControls.xmal代码:

<ListBox Grid.Column="4"  Grid.Row="1" Grid.RowSpan="9" ItemsSource="{Binding ListBoxInput}" Height="165" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="250" ></ListBox>

The SystemControls.xmal.cs code snippet: SystemControls.xmal.cs代码片段:

public partial class SystemControls : UserControl, ISystemControls
{
    IDriver _Driver;
    ISystemControls_VM _VM;
    public SystemControls(IDriver InDriver, ISystemControls_VM InVM)
    {
        _VM = InVM;
        _Driver = InDriver;
        DataContext = new SystemControls_VM(_Driver);
        InitializeComponent();
    }

The SystemControls_VM.cs This should be where the heart of the problem is. SystemControls_VM.cs这应该是问题的核心所在。 I have gotten it to work in the constructor, when i try to add lines later in the code, for example when a user press a button, it does nothing: 我已经在构造函数中使用它了,当我稍后尝试在代码中添加行时,例如当用户按下按钮时,它什么都不做:

public class SystemControls_VM:ViewModelBase, ISystemControls_VM
{
    IDriver _Driver;
    public ObservableCollection<string> _ListBoxInput = new ObservableCollection<string>();


    public SystemControls_VM(IDriver InDriver)
    {
        _Driver = InDriver;

        ListBoxInput.Add("test");//Works here
    }

    public ObservableCollection<string> ListBoxInput
    {
        get 
        { 
            return _ListBoxInput; 
        }
        set
        {
            _ListBoxInput = value;
            //OnPropertyChanged("ListBoxInput");
        }
    }




    public void OnButtonClickGetNextError()
    {
        ListBoxInput.Add("NextErrorClicked");//Does not work here                
    }

    public void OnButtonClickClear()
    {
        ListBoxInput.Clear();//Or Here
    }

Also in case it's needed the OnPropertyChangedEventHandler: 同样,在需要OnPropertyChangedEventHandler的情况下:

namespace XXX.BaseClasses.BaseViewModels
{
    /// <summary>
    /// Provides common functionality for ViewModel classes
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged = delegate{};

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    }    
}

1) Your public property is called _ListBoxInput but you're binding to ListBoxInput (no underscore) . 1) 您的公共属性称为 _ListBoxInput,但您绑定到 ListBoxInput (无下划线) Make _ListBoxInput private. 将_ListBoxInput设为私有。

2) Because the collection is already observable, you don't need the OnPropertyChanged for your listbox to update. 2)因为该集合已经可以观察到,所以不需要OnPropertyChanged来更新列表框。

3) It looks like something might be off with the way you're managing your public vs private ListBoxInput collections. 3)您管理公共ListBoxInput和私有ListBoxInput集合的方式似乎有些问题。 You're calling .Add on your public property (which will immediately raise an event on the observable collection) but then you'll end up adding it to the private collection as well, and then you're calling PropertyChanged on the public property. 您正在调用.Add到您的公共属性上(这将立即在可观察的集合上引发一个事件),但是最终您也将其添加到私有集合中,然后在公共属性上调用PropertyChanged。 It's confusing: try my code below and see how it works. 令人困惑:在下面尝试我的代码,看看它如何工作。 (Note in your constructor you add to _ListBoxInput but in your button click event you add to ListBoxInput.) (请注意,在构造函数中,您添加到_ListBoxInput,但是在按钮单击事件中,您添加到ListBoxInput。)

4) Try adding this.DataContext = this in your constructor 4)尝试在构造函数中添加this.DataContext = this

 public partial class MainWindow : Window { public ObservableCollection<string> ListBoxInput { get; private set; } public MainWindow() { InitializeComponent(); this.ListBoxInput = new ObservableCollection<string>(); this.DataContext = this; } private void AddListBoxEntry_Click(object sender, RoutedEventArgs e) { this.ListBoxInput.Add("Hello " + DateTime.Now.ToString()); } } 

and in the xaml, take a look at the binding Mode . 在xaml中,查看绑定模式

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <ListBox ItemsSource="{Binding ListBoxInput, Mode=OneWay}"
             Height="165" HorizontalAlignment="Left" 
             Name="listBox1" VerticalAlignment="Top" Width="250"  />

    <Button Grid.Column="1" Grid.Row="0" Name="AddListBoxEntry" 
             Margin="0,0,0,158" Click="AddListBoxEntry_Click" >
             <TextBlock>Add</TextBlock>
   </Button>
</Grid>

5) On a separate note, here's another way you could do your INotifyPropertyChanged (I find this cleaner) 5)单独说明,这是您可以执行INotifyPropertyChanged的另一种方法(我找到了这种清洁器)

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate{};

    protected void OnPropertyChanged(string propertyName)
    {
          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

So got the answer from another source, but figured I would post it here for referance. 因此从另一个来源得到了答案,但想出我可以在这里发布以供参考。

So what was happening was that I was setting the data context to one instance of SystemControls_VM while my _VM referance which was handling the button click was going to another instance of SystemControls_VM. 因此发生的事情是,我将数据上下文设置为SystemControls_VM的一个实例,而处理按钮单击的_VM引用正在将SystemContexts_VM的另一个实例设置为数据上下文。 That was also why it looked like the button click was working and the List was being populated but no data was getting to the Control itself 这就是为什么看起来单击按钮起作用并且填充了列表但没有数据进入控件本身的原因

I changed the following section of code and it works: 我更改了以下代码部分,它可以正常工作:

public partial class SystemControls : UserControl, ISystemControls
{
    IDriver _Driver;
    SystemControls_VM _VM;
        public SystemControls(IDriver InDriver, SystemControls_VM InVM)
        {
            _VM = InVM;
            _Driver = InDriver;
            DataContext = InVM;//new SystemControls_VM(_Driver);
            InitializeComponent();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM