WPF: Как сделать привязку DataGrid к динамическим столбцам редактируемой?
Мне нужно привязать некоторые данные к DataGrid с переменным количеством столбцов. Я сделал это, используя следующий код:
int n = 0;
foreach (string title in TitleList)
{
DataGridTextColumn col = new DataGridTextColumn();
col.Header = title;
Binding binding = new Binding(string.Format("DataList[{0}]", n++));
binding.Mode = BindingMode.TwoWay;
col.Binding = binding;
grid.Columns.Add(col);
}
где DataList объявлен как:
public ObservableCollection<double> DataList { get; set; }
и TitleList объявлен как:
public ObservableCollection<string> TitleList { get; set; }
Проблема в том, что, хотя я и указал привязку TwoWay, она действительно односторонняя. Когда я щелкаю ячейку, чтобы попытаться редактировать, я получаю исключение "EditItem" не разрешен для этого представления ". Я что-то пропустил в обязательном выражении?
PS Я нашел статью от Деборы "Заполнение DataGrid динамическими столбцами в приложении Silverlight с использованием MVVM". Однако мне было трудно заставить его работать в моем случае (в частности, я не могу заставить работать привязку заголовка). Даже если это сработало, я все еще сталкиваюсь с такими проблемами, как несовместимые стили ячеек Вот почему я задаюсь вопросом, смогу ли я заставить мой вышеупомянутый код работать - с небольшим изменением?
РЕДАКТИРОВАТЬ: я нашел еще один пост, который может быть связан с моей проблемой: неявное двухстороннее связывание. Это выглядит, если вы связываете список строк с TextBox, используя
<TextBox Text="{Binding}"/>
Вы получите сообщение об ошибке "Двухстороннее связывание требует Path или XPath". Но проблема может быть легко решена с помощью
<TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"/>
или же
<TextBox Text="{Binding .}"/>
Кто-нибудь может дать мне подсказку, если моя проблема может быть решена аналогичным образом?
1 ответ
Вы привязываетесь к индексатору? Можете ли вы показать нам, как выглядит ваше свойство DataList?
я сделал то же самое некоторое время назад с индексированным свойством.
public SomeObjectWithIndexer DataList
{get; set;}
public class SomeObjectWithIndexer
{
public string this
{
get { ... }
set { ... }//<-- you need this one for TwoWay
}
}
РЕДАКТИРОВАТЬ: причина, по которой вы не можете редактировать свое свойство, заключается в том, что вы пытаетесь редактировать "двойное поле". Одним из способов решения этой проблемы было бы заключить ваш двойник в класс с помощью INotifyPropertyChanged.
public class DataListItem
{
public double MyValue { get; set;}//with OnPropertyChanged() and stuff
}
тогда вы можете использовать
ObservableCollection<DataListItem>
и вы можете редактировать свою ценность. вопрос по индексу всегда один и тот же
Binding binding = new Binding(string.Format("DataList[{0}].MyValue", n++));
EDIT2: рабочий пример: просто чтобы показать, что twoway работает
public class DataItem
{
public string Name { get; set; }
public ObservableCollection<DataListItem> DataList { get; set; }
public DataItem()
{
this.DataList = new ObservableCollection<DataListItem>();
}
}
Обертка для двойных:
public class DataListItem
{
private double myValue;
public double MyValue
{
get { return myValue; }
set { myValue = value; }//<-- set breakpoint here to see that edit is working
}
}
пользовательский контроль с сеткой данных
<UserControl x:Class="WpfStackru.IndexCollectionDataGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DataGrid ItemsSource="{Binding MyList}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" />
<DataGridTextColumn Header="Index1" Binding="{Binding Path=DataList[0].MyValue, Mode=TwoWay}" />
<DataGridTextColumn Header="Index2" Binding="{Binding Path=DataList[1].MyValue, Mode=TwoWay}" />
</DataGrid.Columns>
</DataGrid>
</UserControl>
.cs
public partial class IndexCollectionDataGrid : UserControl
{
public IndexCollectionDataGrid()
{
InitializeComponent();
this.MyList = new ObservableCollection<DataItem>();
var m1 = new DataItem() {Name = "test1"};
m1.DataList.Add(new DataListItem() { MyValue = 10 });
m1.DataList.Add(new DataListItem() { MyValue = 20 });
var m2 = new DataItem() { Name = "test2" };
m2.DataList.Add(new DataListItem() { MyValue = 100 });
m2.DataList.Add(new DataListItem() { MyValue = 200 });
this.MyList.Add(m1);
this.MyList.Add(m2);
this.DataContext = this;
}
public ObservableCollection<DataItem> MyList { get; set; }
}
Я надеюсь, что вы получите правильное направление с этим примером.