Maui.DataGrid icon indicating copy to clipboard operation
Maui.DataGrid copied to clipboard

It´s not allowed to use combobox with default Maui.DataGrid PropertyName binding definition

Open PavelSiemko opened this issue 1 year ago • 4 comments

Describe the bug If I use a Combobox/Entry/Picker (or some other user interact control) in a datagrid cell and if I use the default binding (defined as PropertyName and Binding without path), the changes in the model are not reflected.

To Reproduce

  1. Use Maui.DataGrid.Sample project

  2. Add example string test property "TestStr" to model "Team" and define OnPropertyChanged on this property. (e.g. implement INotifyPropertyChanged on model "Team" )

public class Team : INotifyPropertyChanged
{...}
private string _testStr = "someTestValue"; 
public string TestStr 
{ 
    get => _testStr; 
    set 
    { 
        _testStr = value; 
        OnPropertyChanged(nameof(TestStr)); 
    } 
} 
  1. Add 2 DataGridColumns (to MainPage.xaml DataGrid). One with DataTemplate with Entry inside and use default Maui.DataGrid binding and other to only show the value of "TestStr" property
<dg:DataGridColumn Title="Test" PropertyName="TestStr" Width="0.75*" x:Name="TestStrEntryColumn">
    <dg:DataGridColumn.CellTemplate>
        <DataTemplate>
            <Label Text="{Binding}" HorizontalOptions="Center" VerticalOptions="Center" />
        </DataTemplate>
    </dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>
<dg:DataGridColumn Title="Test" Width="0.75*" x:Name="TestStrLabelColumn" PropertyName="TestStr"> 
    <dg:DataGridColumn.CellTemplate> 
        <DataTemplate> 
            <Entry Text="{Binding}" HorizontalOptions="Center" VerticalOptions="Center" /> 
        </DataTemplate> 
    </dg:DataGridColumn.CellTemplate> 
</dg:DataGridColumn> 

Expected behavior If I change the value of TestStr property in Entry column, than the changed value will be reflected to model property value and will be in Label Column

Actual behaviour The changed value is not reflected to model property value and is not reflected to Label column value.

Solution I can´t use default MAUI.Datagrid binding (propertyName in DataGridColumn definition), but default MAUI/WPF binding with defined Path ({Binding Path=TestStr}).

<dg:DataGridColumn Title="Test" Width="0.75*" x:Name="TestStrEntryColumn">
    <dg:DataGridColumn.CellTemplate>
        <DataTemplate>
            <Entry Text="{Binding Path=TestStr}" HorizontalOptions="Center" VerticalOptions="Center" />
        </DataTemplate>
    </dg:DataGridColumn.CellTemplate>
</dg:DataGridColumn>

Additional context The main problem is, that you create your own binding with default Grid.BindingContextProperty, but than the MAUI don´t know which BindableProperty use to in the child of ContentView (e.g. for Entry TextProperty, for ComboBox IsCheckedProperty).

cell.SetBinding(BindingContextProperty,
    new Binding(col.PropertyName, source: BindingContext));

You would have to define every special binding for every special user interact control.

var cv = (ContentView)cell;
if (cv.Content is Entry en)
{
    cell.SetBinding(Entry.TextProperty,
        new Binding(col.PropertyName, source: BindingContext));
}
else if (cv.Content is CheckBox chb)
{
    cell.SetBinding(CheckBox.IsCheckedProperty,
        new Binding(col.PropertyName, source: BindingContext));
}
else
{
    cell.SetBinding(BindingContextProperty,
        new Binding(col.PropertyName, source: BindingContext));
}

So, it is not really a bug, but the usage of your Binding is little bit confused, because you rewrite default Binding from MAUI/WPF and you don´t show, how to use user interact controls in your DataGrid and I think, that this sample is needed. So the best solution might be to show how to use this specials controls in your DataGrid in Maui.DataGrid.Sample project, or change the creation of Binding to the better solution prepared for every user interact control (but I think, that this is not possible).

PavelSiemko avatar Oct 23 '23 14:10 PavelSiemko

Setting the BindingContext to the value of the corresponding PropertyName is the correct behavior that we want, as it allows us to be agnostic to whatever kind of user controls that the user wants. If this results in values not updating, then that would be a MAUI bug.

symbiogenesis avatar Oct 29 '23 01:10 symbiogenesis

I think, that main problem is, that you set Binding on cell to BindingContextProperty, which is default of Grid BindableProperty.

cell.SetBinding(BindingContextProperty,
    new Binding(col.PropertyName, source: BindingContext));

If you want to change the values inside the grid in DataTemplate, you need to specify right BindableProperty of maui component like Entry (Entry.TextProperty), or CheckBox (CheckBox.IsCheckedProperty). So then, you need something like I wrote before:

var cv = (ContentView)cell;
if (cv.Content is Entry en)
{
    cell.SetBinding(Entry.TextProperty,
        new Binding(col.PropertyName, source: BindingContext));
}
else if (cv.Content is CheckBox chb)
{
    cell.SetBinding(CheckBox.IsCheckedProperty,
        new Binding(col.PropertyName, source: BindingContext));
}
else
{
    cell.SetBinding(BindingContextProperty,
        new Binding(col.PropertyName, source: BindingContext));
}

So this is not the bug of MAUI, but maybe of your code.

PavelSiemko avatar Nov 05 '23 19:11 PavelSiemko

I now see what you mean.

I added an inline editing mode to the current main branch, which supports a bunch of data types, and it is binding correctly.

I will see what I can do to make it bidirectionally bind correctly with a custom DataTemplate.

The new EditCellTemplate feature may not be working, given this issue. Will need to test that.

symbiogenesis avatar Jan 04 '24 19:01 symbiogenesis

Is it working better now, when using the latest main branch?

symbiogenesis avatar Jan 24 '24 04:01 symbiogenesis