#c# #wpf #datagridview
#c# #wpf #datagridview
Вопрос:
Я пытаюсь перенести свое приложение Excel в WPF datagrid. Я собираюсь ввести данные в столбец A, а в столбце B я хотел бы произвести вычисление, взяв предыдущую ячейку и текущую ячейку столбца, и добавить предыдущую ячейку столбца B. пример вычисления: B2 = B1 (A2-A1). Каков наилучший подход к этому?
Комментарии:
1. Подождите. Только что поймал это. Под «предыдущей ячейкой» вы имеете в виду предыдущую строку ?
2. Да, ячейка предыдущей строки того же столбца. Текущая строка равна 2, поэтому в ячейке (B2) я хотел бы произвести вычисление = B1 (A2-A1)
Ответ №1:
Лично я бы начал с создания класса, который представляет записи, и реализовал INotifyPropertyChanged в этом классе.
public class recordObject : INotifyPropertyChanged
{
private int a;
public int A
{
get
{
return a;
}
set
{
a = value;
OnPropertyChanged("A");
}
}
private int b;
public int B
{
get
{
return b;
}
set
{
b = value;
OnPropertyChanged("B");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Затем в вашем коде позади окна, в котором вы показываете datagrid, вы захотите подписаться на PropertyChanged для каждого объекта в списке. Тогда вам пришлось бы вручную вычислять значения столбцов всякий раз, когда эти свойства изменялись. Крик, я знаю, но это сработало бы.
Событие изменения свойства будет выглядеть следующим образом:
void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var objectList = DataGrid.ItemsSource as List<recordObject>;
var myRecord = sender as recordObject;
if (objectList != null amp;amp; myRecord != null)
{
int idx = objectList.IndexOf(myRecord);
// Perform your calculations here using idx to access records before and after the current record
// making sure to check for list boundaries for top and bottom.
// Also note that this will likely kick off cascading event calls so make sure you're only changing
// the previous or following record object.
}
}
Если вы подключаете это событие ко всем записям в вашем связанном списке, то оно будет срабатывать при каждом изменении любого свойства. В приведенном выше классе это применимо как к A, так и B. Вы можете отфильтровать, какие свойства вам интересны для мониторинга, с помощью e.propertyName (простое сравнение строк) и соответствующим образом настроить бизнес-логику. Если вы хотите сохранить инкапсуляцию или, по крайней мере, поместить бизнес-логику для объекта в сам объект, этот метод может быть статическим для класса recordObject . Однако вам пришлось бы предусмотреть получение datagrid из этого статического метода (вероятно, через статическое свойство в вашем окне). Итак:
public static void recordObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
и подключенный таким образом:
record.PropertyChanged = new PropertyChangedEventHandler(recordObject.recordObject_PropertyChanged);
Комментарии:
1. Вау, это действительно подробный ответ, спасибо за это. Насколько я понял, ваш ответ сосредоточен на автоматическом обновлении столбца B, что приветствуется, но не на данном этапе. То, что я ищу прямо сейчас, — это бизнес-логика за сценой.
2. Не мог бы ты быть более конкретным, Джим? Все, что вы получили с помощью бизнес-логики в вашем вопросе, это B2 = B1 (A2-A1). Я думал, что ваш вопрос был более общим, поэтому я не уверен, к чему вы клоните.
3. я отмечу это как ответ, однако я должен изучить то, что вы предложили, и сделать много попыток и ошибок 🙂
4. В ответ на ваш комментарий меня действительно интересуют примечания, которые вы делаете в своем коде (например … // Выполните свои вычисления здесь, используя idx … скорее всего, запустится каскадное событие ….. и т.д.). В идеале я бы поместил эту логику в recordObject, но это кажется невозможным.
5. Не исключено. Просто создайте статическое свойство DataGrid в вашем окне и назначьте ему свою datagrid в Window_Loaded. Таким образом, вы можете ссылаться на свою коллекцию объектов как MyWindow. MyDataGrid. Источник элементов.
Ответ №2:
Лучше всего реализовать эту логику в классе и привязать сетку к соответствующим свойствам. Например:
class SomeData
{
int A { get; set; }
int B { get; set; }
int AminusB { get { return A - B; } }
}
Комментарии:
1. Это точное решение не сработало бы для того, чего пытаются достичь. Каждый экземпляр SomeData должен был бы иметь ссылку на предыдущие SomeData, чтобы вычислять B каждый раз в зависимости от значений A и B в предыдущих SomeData.
2. Хороший улов, Адам. Я также пропустил это в своем ответе.
3. Спасибо, я внедрил ваше решение (Ник и Джейкоб), чтобы выполнить вычисление в той же строке без каких-либо проблем. Однако я все еще не могу понять, как получить ячейку предыдущей строки и добавить ее в ячейку текущей строки B2 = B1 (A2-A1)