2

リストボックスコントロールのItemsSourceへのバインドに問題があります。ユーザーが特定のアクションを実行するときに、リストボックスにテキスト行を追加できるようにしたいと思います。

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>

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();
    }

SystemControls_VM.csこれは、問題の核心となる場所です。コンストラクターで機能するようになりました。コードの後半で行を追加しようとすると、たとえば、ユーザーがボタンを押しても何も起こりません。

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
    }

また、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));
    }

    }    
}
4

2 に答える 2

1

1) Your public property is called _ListBoxInput but you're binding to ListBoxInput (no underscore). Make _ListBoxInput private.

2) Because the collection is already observable, you don't need the OnPropertyChanged for your listbox to update.

3) It looks like something might be off with the way you're managing your public vs private ListBoxInput collections. 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. 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.)

4) Try adding this.DataContext = this in your constructor

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.

<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)

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

    protected void OnPropertyChanged(string propertyName)
    {
          PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
于 2013-02-15T19:09:58.700 に答える
0

それで、別の情報源から答えを得ました、しかし、私が参照のためにそれをここに投稿するだろうと考えました。

つまり、ボタンのクリックを処理していた_VM参照がSystemControls_VMの別のインスタンスに移動しているときに、データコンテキストをSystemControls_VMの1つのインスタンスに設定していました。これが、ボタンのクリックが機能し、リストにデータが入力されているように見えたが、コントロール自体にデータが到達していない理由でもあります。

コードの次のセクションを変更しましたが、機能します。

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();
        }
于 2013-02-15T20:39:19.360 に答える