Привязка WPF к многомерному массиву в xaml
мне трудно сформулировать строку XAML для ссылки на определенный элемент в многомерном массиве.
DataContext содержит следующие строки:
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; } }
XAML содержит следующие строки:
<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>
привязка к OneDimension
и Jagged
работать, как ожидалось. Привязка к TwoDimension
не работает и кажется неправильным, однако XAML не позволяет мне использовать разделитель ,
так я не знаю, как привязать к двум двумерный массив.
это:
<Button Content="{Binding TwoDimension[1,1]}" Width="100" Height="50" />
не компилируется, поскольку XAML интерпретируется как имеющий два аргумента для конструктора привязки. Есть ли способ избежать парсера или есть другой способ написать это, о котором я не знаю?
EDIT:
Я только что узнал, что можно избежать сепаратора, как это
<Button Content="{Binding TwoDimension[1,1]}" Width="100" Height="50" />
или просто окружите аргумент маркерами, такими как это
<Button Content="{Binding 'TwoDimension[1,1]'}" Width="100" Height="50" />
однако эта строка теперь приводит к исключению:System.ArgumentException
{"Das Array war kein Eindimensionales Array."} к сожалению, C# установил себя на моем родном языке-раздражает, как дерьмо... так это примерно переводится как {"массив массив onedimensionale."}
действительно ли невозможно связать многомерные массивы?
2 ответов
можно привязать к двумерный массив с помощью MultivalueConverter определить так :
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();
}
}
что MultiDimensionalCoverter получает 3 параметра, двухмерный массив плюс два индекса, и Xaml будет выглядеть так:
<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>
определения показателей свойств в виртуальной машине, вероятно, более уместно, я использую фиксированное значение только для демонстрации.
по умолчанию WPF XAML не разрешает привязку к 2D-массиву, как это. Только в 1D массивы. Однако, нет ничего невозможного. Просто много времени. Для этого вам нужно будет создать пользовательский класс и использовать его как способ привязки.
/// <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;
}
}
затем вы можете привязаться к XAML:
<TextBlock Text="{Binding MyBindableTwoDArray[2-5]}"/>
источник решения.
Это может повлиять на производительность, что приводит меня к вопросу использования многомерного массива Для начала? Вы можете использовать списки, которые возможно, это более простая реализация. Взгляните на данное решение.