This is a migrated thread and some comments may be shown as answers.

Problem with IsReadOnlyBinding and custom DataTable and DataRow objects

7 Answers 237 Views
GridView
This is a migrated thread and some comments may be shown as answers.
J
Top achievements
Rank 1
J asked on 04 Oct 2017, 05:09 PM

I have created a custom data row and a custom data table class by extending both MyDataRow and MyDataTable classes. MyDataRow and MyDataTable are defined in my data set file (.xsd). I.e., I'm using a real database. MyDataTable has a few fields (Id, Status, DateCreated, etc...).

In XAML, I have set RadGridView control's ItemsSource property to a DataView object (bound to ViewModel's property). In short, new MyDataTable().DefaultView. Naturally it's been filled with data from the database before getting the DefaultView.

The reason why I created the custom classes was that I want to add additional property (IsReadOnly) to be used together with IsReadOnlyBinding and I don't want to change the database or the data set file structure.

This is how I have created the custom classes (the second answer): https://stackoverflow.com/questions/3101412/how-to-extend-datarow-and-datatable-in-c-sharp-with-additional-properties-and-me

When I set grid's IsReadOnlyBinding="{Binding IsReadOnly}", an exception is thrown when try to add a new row or edit an existing one. The exception says: Property with specified name: IsReadOnly cannot be found on component: System.Data.DataRowView

However, if I set IsReadOnlyBinding="{Binding Status}", it works. Status field already exist in my database table.

Is the grid using internally the data set schema (.xsd) or what might cause this? Any ideas how to solve this?

I am trying to accomplish functionality where rows cannot be edited until I click a modify button (which sets IsReadOnly to false for the selected row) but I still want to add new rows using the grid's new row button.

I wish I could attach actual code but there's a lot of it and it's not easy to copy-paste it here. I could try to put together a test project if my description is not clear enough.

7 Answers, 1 is accepted

Sort by
0
J
Top achievements
Rank 1
answered on 04 Oct 2017, 05:22 PM

Here are the extended classes just in case:

public class ExtendedTable : MyDataSet.MyDataTable
{
    public ExtendedTable()  : base()
    {
    }
 
    public ExtendedTable(DataTable table) : base(table)
    {
    }
 
    public ExtendedTable(SerializationInfo info, StreamingContext context) : base(info, context)
    {
    }
 
    protected override Type GetRowType()
    {
        return typeof(ExtendedRow);
    }
 
    protected override DataRow NewRowFromBuilder(DataRowBuilder builder)
    {
        return new ExtendedRow(builder);
    }
}
 
[Serializable]
public class ExtendedRow : MyDataSet.MyRow, INotifyPropertyChanged
{
    private bool isReadOnly = false;
 
    public event PropertyChangedEventHandler PropertyChanged = null;
 
    public ExtendedRow() : base(null)
    {
    }
 
    public ExtendedRow(DataRowBuilder builder) : base(builder)
    {
    }
 
    public bool IsReadOnly
    {
        get
        {
            return this.isReadOnly;
        }
 
        set
        {
            if (this.isReadOnly != value)
            {
                this.isReadOnly = value;
 
                this.NotifyPropertyChanged("IsReadOnly");
            }
        }
    }
 
    private void NotifyPropertyChanged(String propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
0
Martin Ivanov
Telerik team
answered on 09 Oct 2017, 12:49 PM
Hello J,

The exception occurs because the DefaultView of DataTable works with DataRowView items instead of the DataRows. Since the DataRowView doesn't have a IsReadOnly property, the reported exception is thrown. Actually, in the latest version of UI for WPF the exception is not thrown but silently caught. However, the binding still won't work. 

I can suggest you two approaches to achieve your requirement.
  • Instead of using the DataTable class, you can create viewmodel wrappers and bind the RadGridView control to a collection of the wrappers. For example:
    public class TableRowWrapper
    {
        public string Name { get; set; }
        public DateTime DateOfBirth { get; set; }
        public bool IsReadOnly { get; set; }
        // etc.
    }
  • Alternatively, instead of using the IsReadOnlyBinding you can subscribe to the BeginingEdit event of RadGridView and if the ExtendedRow IsReadOnly property is set to True, cancel the editing. Here is an example in code:
    private void RadGridView_BeginningEdit(object sender, GridViewBeginningEditRoutedEventArgs e)
    {
        var dataRowView = e.Row.Item as DataRowView;
        if (dataRowView != null)
        {
            var extendedRow = (ExtendedRow)dataRowView.Row;
            e.Cancel = extendedRow.IsReadOnly;
        }           
    }
I hope this helps.

Regards,
Martin Ivanov
Progress Telerik
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
0
J
Top achievements
Rank 1
answered on 13 Oct 2017, 04:02 PM

I went with the first approach, row wrapper, and added an additional property IsReadOnly.

However, I'm still unable to make the column show a modifiable text box with a click of a button. My button's click event handler invokes the BeginEdit method (which seem to return false all the time). After clicking the button, if I click the grid view row, it then shows the modifiable text box.

If I remove ReadOnlyBinding property setting from XAML, the text box is shown when I click the button.

You can test this with your demo project: Read Only Binding in GridView's examples in your SDK Samples Browser demo application. Just add new button to the current UI layout.

Here's the XAML code for the bottom grid view:

<telerik:RadGridView
            x:Name="grid"
            Grid.Row="4"
            ItemsSource="{Binding Clubs}"
            AutoGenerateColumns="False"   
            ColumnWidth="*"
            IsReadOnlyBinding="{Binding IsNameReadOnly}"
            SelectedItem="{Binding SelectedItem}">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/>
                <!--<telerik:GridViewDataColumn DataMemberBinding="{Binding Established}"
                                            Header="Est."
                                            DataFormatString="{}{0:yyyy}"/>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding StadiumCapacity}"
                                            Header="Stadium" />-->
            </telerik:RadGridView.Columns>
</telerik:RadGridView>

 

The last two columns are intentionally disabled because I have only one column in my application.

And here's the button click event handler:

private void Button_Click(object sender, RoutedEventArgs e)
{
    ((this.DataContext as MyViewModel).SelectedItem as Club).IsNameReadOnly = false;
 
    Boolean b = grid.BeginEdit();
}

 

IsNameReadOnly would be set back to true when the new row is validated (i.e., it's again read-only until the next button click), but it's not important at the moment.

As a side not, I'm using MVVM so I prefer not to use events. On the other hand, I have already created a new class that inherits from your grid view class, to allow me to use row validation events, so I guess events are okay...

0
J
Top achievements
Rank 1
answered on 13 Oct 2017, 04:09 PM
Also, modify the Club.GetClubs method so that all the clubs have IsNameReadOnly = true.
0
J
Top achievements
Rank 1
answered on 13 Oct 2017, 04:13 PM

In MainWindows constructor:

this.grid.RowEditEnded += Grid_RowEditEnded;

 

Here the event handler code:

private void Grid_RowEditEnded(object sender, Telerik.Windows.Controls.GridViewRowEditEndedEventArgs e)
{
        Club c = (this.DataContext as MyViewModel).SelectedItem as Club;
        c.IsNameReadOnly = true;
 }
0
J
Top achievements
Rank 1
answered on 13 Oct 2017, 04:25 PM

Looks like I got it working like this (not sure if this is a recommended way to handle this, though):

private void Button_Click(object sender, RoutedEventArgs e)
{
    Club c = (this.DataContext as MyViewModel).SelectedItem as Club;
    c.IsNameReadOnly = false;
 
    System.Windows.Data.Binding binding = grid.IsReadOnlyBinding;
 
    grid.IsReadOnlyBinding = null;
 
    Boolean b = grid.BeginEdit();
 
    grid.IsReadOnlyBinding = binding;
}

 

Well, at least this whole thing for you information, if this is a bug in the grid control.

Let me know your thoughts. 

 

0
Martin Ivanov
Telerik team
answered on 18 Oct 2017, 01:00 PM
Hi J,

I am glad to hear you managed to achieve your requirement.

As for the reported behavior, I am not sure why this happens, but I will guess that the edit mode is set up to start on a single click which triggers the begin edit method when you click on the button in the row.

Regards,
Martin Ivanov
Progress Telerik
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
Tags
GridView
Asked by
J
Top achievements
Rank 1
Answers by
J
Top achievements
Rank 1
Martin Ivanov
Telerik team
Share this question
or