WPF Binding to multidimensional array in the xaml

10,813

Solution 1

You can bind to a Two dimensional array using a MultivalueConverter defined like this :

 class MultiDimensionalCoverter:IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return (values[0] as String[,])[(int) values[1], (int) values[2]];  
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

that MultiDimensionalCoverter get 3 parameters, the Two Dimention array plus the two indexes, and the Xaml will be like this :

<Window.Resources>
        <wpfApp:MultiDimensionalCoverter x:Key="MultiDimensionalCoverter"/>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Button Content="{Binding OneDimension[1]}" Width="100" Height="50" />
            <Button Content="{Binding Jagged[1][1]}" Width="100" Height="50" />
            <Button Width="100" Height="50" >
                <Button.Resources>
                    <system:Int32 x:Key="1">1</system:Int32>
                </Button.Resources>
                <Button.Content>
                    <MultiBinding Converter="{StaticResource MultiDimensionalCoverter}">
                        <Binding Path="TwoDimension"/>
                        <Binding Source="{StaticResource 1}"/>
                        <Binding Source="{StaticResource 1}"/>
                    </MultiBinding>
                </Button.Content>
            </Button>
        </StackPanel>
    </Grid>

defining the indexes as properties in your VM is probably more appropriate, i am using fixed value only to demonstrate.

Solution 2

By default WPF XAML does not allow binding to a 2D array like this. Only 1D arrays. However, nothing is impossible. Just time consuming. You will have to create a custom class in order to do this and use that as a way of binding.

/// <summary>
/// This class is a bindable encapsulation of a 2D array.
/// </summary>
/// <typeparam name="T"></typeparam>
public class BindableTwoDArray<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void Notify(string property)
    {
        var pc = PropertyChanged;
        if (pc != null)
            pc(this, new PropertyChangedEventArgs(property));
    }

    T[,] data;

    public T this[int c1, int c2]
    {
        get { return data[c1, c2]; }
        set
        {
            data[c1, c2] = value;
            Notify(Binding.IndexerName);
        }
    }

    public string GetStringIndex(int c1, int c2)
    {
        return c1.ToString() + "-" + c2.ToString();
    }

    private void SplitIndex(string index, out int c1, out int c2)
    {
        var parts = index.Split('-');
        if (parts.Length != 2)
            throw new ArgumentException("The provided index is not valid");

        c1 = int.Parse(parts[0]);
        c2 = int.Parse(parts[1]);
    }

    public T this[string index]
    {
        get
        {
            int c1, c2;
            SplitIndex(index, out c1, out c2);
            return data[c1, c2]; 
        }
        set
        {
            int c1, c2;
            SplitIndex(index, out c1, out c2);
            data[c1, c2] = value;
            Notify(Binding.IndexerName);
        }
    }

    public BindableTwoDArray(int size1, int size2)
    {
        data = new T[size1, size2];
    }

    public static implicit operator T[,](BindableTwoDArray<T> a)
    {
        return a.data;
    }
}

Then you can bind to XAML:

<TextBlock Text="{Binding MyBindableTwoDArray[2-5]}"/>

Source of solution.

This may affect performance which leads me to question using a multidimensional array to begin with? You may use lists which may be an easier implementation. Take a look at this solution.

Share:
10,813
Johannes
Author by

Johannes

Updated on July 25, 2022

Comments

  • Johannes
    Johannes almost 2 years

    I have trouble to formulate the XAML string to link to a specific element in a multidimensional array.

    The DataContext contains the following lines:

        private String[] _OneDimension = { "[0]", "[1]" };
        private String[][] _Jagged = { new String[] { "[0,0]", "[0,1]" }, new String[] { "[1,0]", "[1,1]" } };
        private String[,] _TwoDimension = { { "[0,0]", "[0,1]" }, { "[1,0]", "[1,1]" } };
    
        public String[] OneDimension { get { return _OneDimension; } }
        public String[][] Jagged { get { return _Jagged; } }
        public String[,] TwoDimension { get { return _TwoDimension; } }
    

    The XAML contains the following lines:

        <StackPanel>
            <Button Content="{Binding OneDimension[1]}" Width="100" Height="50" />
            <Button Content="{Binding Jagged[1][1]}" Width="100" Height="50" />
            <Button Content="{Binding TwoDimension[1][1]}" Width="100" Height="50" />
        </StackPanel>
    

    The binding to OneDimension and Jagged work as expected. The binding to TwoDimension does not work and appears to be wrong, however the XAML does not allow me to use the separator , so I do not know how to bind to a two dimensional array.

    This:

            <Button Content="{Binding TwoDimension[1,1]}" Width="100" Height="50" />
    

    does not compile because the XAML gets interpreted as having two arguments for the Binding Constructor. Is there some way to escape the parser or is there another way of writing this that I am not aware of?


    EDIT:

    I just found out that it is possible to escape the separator like this

    <Button Content="{Binding TwoDimension[1\,1]}" Width="100" Height="50" />
    

    or just surround the argument with markers like this

    <Button Content="{Binding 'TwoDimension[1,1]'}" Width="100" Height="50" />
    

    However this line now leads to an exception: System.ArgumentException {"Das Array war kein eindimensionales Array."} unfortunatelly C# installed itself in my native language - annoying as shit... so this roughly translates to {"The Array was not a onedimensionale Array."}

    Is it actually impossible to bind multidimensional arrays?

    • sa_ddam213
      sa_ddam213 about 11 years
      As far as I am aware it is not possible to bind multidimensional arrays in pure Xaml, you will have to create an IValueConverter to do the work.
    • Johannes
      Johannes about 11 years
      Hmmm, to do that i would have to know the type... that would be Array... but there is a ValueConverter for array - i am sure of that. Can i inject my onw?
    • Ayyappan Subramanian
      Ayyappan Subramanian about 9 years
      Try this link. Hope it helps nicoschertler.wordpress.com/2014/05/22/…