Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to make TwoWay binding with templates? #32

Open
odinsacred opened this issue May 19, 2018 · 10 comments
Open

How to make TwoWay binding with templates? #32

odinsacred opened this issue May 19, 2018 · 10 comments

Comments

@odinsacred
Copy link

Hello! Can anybody help me? I wanna bind 2D int array to DataGrid, but I don't understand how to create TwoWay binding. Now I'm use this code:

<DataGrid Grid.Column="1" Grid.Row="1" x:Name="AutoColumns"
    dataGrid2D:ItemsSource.Array2D="{Binding Path=Data2D, Mode=TwoWay}"
    dataGrid2D:ItemsSource.ColumnHeadersSource="{Binding ColumnHeaders}"
    dataGrid2D:ItemsSource.RowHeadersSource="{Binding RowHeaders}"
    ColumnWidth="50"
    SelectionUnit="Cell"
    IsReadOnly="False"
    IsEnabled="True">
<dataGrid2D:Cell.Template>
<DataTemplate>
    <TextBlock Text="{Binding Path=., StringFormat=X4}" IsEnabled="true"/>
</DataTemplate>
</dataGrid2D:Cell.Template>
    <dataGrid2D:Cell.EditingTemplate>
    <DataTemplate>
        <TextBox Text="{Binding Path=., StringFormat=X4}" />
    </DataTemplate>
</dataGrid2D:Cell.EditingTemplate>
</DataGrid>

Also I'm tried to add an attributes like "Mode=TwoWay, BindsDirectlyToSource=True, UpdateSourceTrigger=LostFocus, NotifyOnSourceUpdated=True" In data templates, but it's do nothing effect. Now it's allow me to entering some numbers in cells, but not save to my array. And one detail - everything work good without templates, but I need them.

@odinsacred odinsacred changed the title How to make TwoWay binding with templates How to make TwoWay binding with templates? May 19, 2018
@JohanLarsson
Copy link
Member

Is the type you are binding to int[,]? If so you need to wrap the elements and bind to a property. This is the same limitation as if you do:

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Values}">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Value">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding .}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

with:

public class ViewModel
{
    public ObservableCollection<int> Values { get; } = new ObservableCollection<int> {1, 2, 3};
}

@odinsacred
Copy link
Author

Thanks for answer! Yes, it's about int[,]. I'm novice in WPF, so I'm not completely understood this
public ObservableCollection<int> Values { get; } = new ObservableCollection<int> {1, 2, 3};
This is an 1D array, right? So for 2D array I'm need
public ObservableCollection<int> Values { get; } = new ObservableCollection<int> {{1, 2, 3}, {1,2,3}};
Isn't it?

@odinsacred
Copy link
Author

odinsacred commented May 19, 2018

What I want: view and edit values in HEX format, in addition I need to set names of rows and columns. Today I'm readed issue "Scientific Notation for Numeric Data", created by kaneorotar, he has a similar problem. Maybe we will try to write a complete example with templates and twoWay binding for other people, who will have this problem in the future?

@odinsacred
Copy link
Author

odinsacred commented May 19, 2018

Now I'm try do this: (but it's not working)
C# code:

        public ObservableCollection<int[,]> Values
        {
            get => this.values;

            set
            {
                if (Equals(value, this.values))
                {
                    return;
                }

                this.values = value;
                NotifyOfPropertyChange(() => Values);
            }
        }

// Constructor:
    ObservableCollection<int[,]> a = new ObservableCollection<int[,]>();
    a.Add(new int[,] { { 1, 2, 3 }, { 1, 2, 3 } });
    Values = a;

XAML code:

<DataGrid Grid.Column="1" Grid.Row="1" x:Name="AutoColumns"
    dataGrid2D:ItemsSource.Array2D="{Binding Path=Values}"
    dataGrid2D:ItemsSource.ColumnHeadersSource="{Binding ColumnHeaders}"
    dataGrid2D:ItemsSource.RowHeadersSource="{Binding RowHeaders}"
    ColumnWidth="50"
    SelectionUnit="Cell"
    IsReadOnly="False"
    IsEnabled="True">
    <dataGrid2D:Cell.Template>
        <DataTemplate>
            <TextBlock Text="{Binding Path=., StringFormat=X4}"/>
        </DataTemplate>
    </dataGrid2D:Cell.Template>
        <dataGrid2D:Cell.EditingTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Path=., StringFormat=X4}" />
            </DataTemplate>
        </dataGrid2D:Cell.EditingTemplate>
</DataGrid>

@JohanLarsson
Copy link
Member

The code was not a suggestion for a fix, it was an example of the limitation you hit.

@odinsacred
Copy link
Author

And so, should I hope for comlete example, or I must create it by myself?

@JohanLarsson
Copy link
Member

I'll ping you if I write one but not sure when I will find the time.

@odinsacred
Copy link
Author

Ok, anyway, thanks for support))

@FoggyFinder
Copy link
Contributor

FoggyFinder commented May 19, 2018

@odinsacred for now you can use converter like this:

  public class EditableInt2DConverter : IValueConverter
    {
        class ItemWrapper
        {
            int[,] container;
            int i, j;

            public ItemWrapper(int[,] container, int i, int j)
            {
                this.container = container;
                this.i = i;
                this.j = j;
            }

            public int Value
            {
                get => container[i, j];
                set => container[i, j] = value;
            }
        }

        public object Convert(object value, Type targetType, object p, CultureInfo ci)
        {
            var array2d = (int[,])value;
            var n = array2d.GetLength(0);
            ItemWrapper[,] items = new ItemWrapper[n, n];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    items[i,j] = new ItemWrapper(array2d, i, j);
            return items;
        }

        public object ConvertBack(object value, Type targetType, object p, CultureInfo ci) =>
            throw new NotSupportedException();
    }
dataGrid2D:ItemsSource.Array2D="{Binding Path=Data2D, Converter={StaticResource EditableInt2DConverter}}"

so, you will bind to Value in templates.

            <dataGrid2D:Cell.Template>
                <DataTemplate>
                    <TextBlock IsEnabled="true" Text="{Binding Path=Value, StringFormat=X4}" />
                </DataTemplate>
            </dataGrid2D:Cell.Template>
            <dataGrid2D:Cell.EditingTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding Path=Value, StringFormat=X4}" />
                </DataTemplate>
            </dataGrid2D:Cell.EditingTemplate>

@odinsacred
Copy link
Author

@FoggyFinder Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants