WPF: Как сделать привязку DataGrid к динамическим столбцам редактируемой? - PullRequest
1 голос
/ 12 мая 2011

Мне нужно привязать некоторые данные к 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» не разрешен для этого представления ». Я что-то пропустил в обязательном выражении?

P.S. Я нашел статью Деборы «Заполнение таблицы данных динамическими столбцами в приложении Silverlight с использованием MVVM» . Однако мне было трудно заставить его работать для моего случая (в частности, я не могу заставить работать привязку заголовка). Даже если это сработало, я все еще сталкиваюсь с такими проблемами, как несовместимые стили ячеек. Вот почему я задаюсь вопросом, смогу ли я заставить мой вышеупомянутый код работать - с небольшим изменением?

РЕДАКТИРОВАТЬ: Я нашел другой пост, который может быть связан с моей проблемой: Неявная двусторонняя привязка . Выглядит, если вы связываете список строк с TextBox, используя

<TextBox Text="{Binding}"/>

Вы получите сообщение об ошибке типа «Для двусторонней привязки требуется путь или XPath». Но проблема может быть легко решена с помощью

<TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self}}"/>

или

<TextBox Text="{Binding .}"/>

Кто-нибудь может дать мне подсказку, если моя проблема может быть решена подобным образом?

1 Ответ

2 голосов
/ 12 мая 2011

Вы привязываетесь к индексатору?Можете ли вы показать нам, как выглядит ваше свойство 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>();
    }
}

Оболочка для double:

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 с сеткой данных

<UserControl x:Class="WpfStackoverflow.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; }
}

Я надеюсь, что вы получите правильное направление с этим примером.

...