0
votes

I Have a DataGrid bounded to SelectedQueryView.SelectedColumns where SelectedQueryView is:

public QueryViewItem SelectedQueryView { get; set; }

and QueryViewItem is:

public class QueryViewItem : ViewModelBase
{
    private string _viewIcon;
    private string _viewName;
    private string _tableName;

    public string ViewIcon
    {
        [DebuggerStepThrough]
        get { return _viewIcon; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewIcon)
            {
                _viewIcon = value;
                OnPropertyChanged("ViewIcon");
            }
        }
    }
    public string ViewName
    {
        [DebuggerStepThrough]
        get { return _viewName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewName)
            {
                _viewName = value;
                OnPropertyChanged("ViewName");
            }
        }
    }

    public string TableName
    {
        [DebuggerStepThrough]
        get { return _tableName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableName)
            {
                _tableName = value;
                OnPropertyChanged("TableName");
            }
        }
    }

    public ObservableCollection<TableColumn> SelectedColumns { get; set; }
}

And, TableColumn is:

public class TableColumn : ViewModelBase
{
    private string _tableSource;
    public string TableSource
    {
        [DebuggerStepThrough]
        get { return _tableSource; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableSource)
            {
                _tableSource = value;
                OnPropertyChanged("TableSource");
            }
        }
    }
    private string _colName;
    public string ColName
    {
        [DebuggerStepThrough]
        get { return _colName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _colName)
            {
                _colName = value;
                OnPropertyChanged("ColName");
            }
        }
    }
    private string _customName;
    public string CustomName
    {
        [DebuggerStepThrough]
        get { return _customName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _customName)
            {
                _customName = value;
                OnPropertyChanged("CustomName");
            }
        }
    }

    public override string ToString()
    {
        string sRet;

        if(ColName.Equals("*"))
            sRet = TableSource + "." + ColName;
        else
            sRet = TableSource + "." + ColName + " AS " + CustomName;
        return sRet;
    }
}

And, finally, ViewModelBase is:

public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(sender, e);
    }

    protected virtual void OnPropertyChanged(string PropertyName)
    {
        OnPropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
    }
}

The problem is that, when I add a field to SelectedQueryView.SelectedColumns, the associated DataGrid is not updated, even if SelectedColumns is an ObservableCollection.

Xaml

<DataGrid Grid.Row="0" Grid.Column="2" ItemsSource="{Binding Path=SelectedQueryView.SelectedColumns}" BorderBrush="Black" Margin="5" SelectedItem="{Binding Path=SelectedDestColumn}" AutoGenerateColumns="False" GridLinesVisibility="None" CanUserAddRows="False" RowEditEnding="DataGrid_RowEditEnding" RowHeaderWidth="0" Background="White">
<DataGrid.Columns>
    <DataGridTextColumn Header="Name" Width="*" Binding="{Binding Path=ColName}" IsReadOnly="True"/>
     <DataGridTextColumn Header="Custom Name" Width="*" Binding="{Binding Path=CustomName}" />
 </DataGrid.Columns>
</DataGrid>

Can someone explain me why and how to solve this problem?

2
The QueryViewItem class needs to implement property change notifications. Do you need to see a snippet of how to get started? - Gayot Fow
Yes, thanks; it would be useful. - rPulvi
See if this answer helps you "get it" - Gayot Fow
@Riccardo if it is an observablecollection then adding object to it should be updated automatically on UI..you need not call PropertyChanged to add item on the view in this case.. can you share how you are adding elements in collection and binding your collection to view - Nitin
@nit Here is how I add elements in the collection: SelectedQueryView.SelectedColumns.Add(column); where column is a TableColumn object - rPulvi

2 Answers

0
votes

Your classes need to inherit from INotifyPropertyChanged. For a start, change your TableColumn class to this...

   public class TableColumn : INotifyPropertyChanged
    {
        private string _tableSource;
        public string TableSource
        {
            [DebuggerStepThrough]
            get { return _tableSource; }
            [DebuggerStepThrough]
            set
            {
                if (value != _tableSource)
                {
                    _tableSource = value;
                    OnPropertyChanged("TableSource");
                }
            }
        }
        private string _colName;
        public string ColName
        {
            [DebuggerStepThrough]
            get { return _colName; }
            [DebuggerStepThrough]
            set
            {
                if (value != _colName)
                {
                    _colName = value;
                    OnPropertyChanged("ColName");
                }
            }
        }
        private string _customName;
        public string CustomName
        {
            [DebuggerStepThrough]
            get { return _customName; }
            [DebuggerStepThrough]
            set
            {
                if (value != _customName)
                {
                    _customName = value;
                    OnPropertyChanged("CustomName");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string name)
        {
            var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

This will cause your class to issue the notification to the WPF binding engine so that changes will be applied on the user surface. Using the notify pattern on all your view model classes is highly recommended for this reason.

This code compiles clean in VS2013. The same pattern must be applied to your QueryViewItem class so that the binding engine can locate the class (but not for the SelectedColumns member because it already implements INPC).

It would look like this...

public class QueryViewItem : INotifyPropertyChanged
{
    public ObservableCollection<TableColumn> SelectedColumns { get; set; }
    private string _viewIcon;
    public string ViewIcon
    {
        [DebuggerStepThrough]
        get { return _viewIcon; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewIcon)
            {
                _viewIcon = value;
                OnPropertyChanged("ViewIcon");
            }
        }
    }
    private string _viewName;
    public string ViewName
    {
        [DebuggerStepThrough]
        get { return _viewName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _viewName)
            {
                _viewName = value;
                OnPropertyChanged("ViewName");
            }
        }
    }
    private string _tableName;
    public string TableName
    {
        [DebuggerStepThrough]
        get { return _tableName; }
        [DebuggerStepThrough]
        set
        {
            if (value != _tableName)
            {
                _tableName = value;
                OnPropertyChanged("TableName");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}
0
votes

Let me see if I understand the crux of this problem. Judging by your edits, I believe that initially, your problem was that you weren't implementing the INotifyPropertyChanged interface, so kudos to @GayotFow for pointing that out. However, now that you have added your ViewModelBase class, it now seems as though your problem is that your UI is not updating when you add elements into your SelectedQueryView.SelectedColumns collection.

If that is correct, then I believe that your problem is still down to a lack of update notification. According to one of your comments, you add elements to your collection like this:

SelectedQueryView.SelectedColumns.Add(column); 

I believe that that is your problem. Despite what everybody is saying about the ObservableCollection automatically updating the UI, I think that if you added a call to your OnPropertyChanged method here, then you would see the update in the UI. Try this:

SelectedQueryView.SelectedColumns.Add(column); 
OnPropertyChanged("SelectedColumns");