Я пытаюсь создать сетку данных, в которой в качестве первой ячейки используется поле со списком. У меня странное поведение при добавлении строки в: - Если я выбираю элемент в поле со списком и перехожу к следующей ячейке, выбор поля со списком очищается. Это происходит только в том случае, если в этой строке ранее ничего не заполнялось - ObervableCollection
, хранящий данные из сетки данных, не обновляется.
Я, должно быть, что-то не так с привязками, но не могу разобраться что ...
Вот код ( на основе этого урока )
GridDataModel
namespace InteractiveGraph.Grid
{
public class DoliInput : ObservableObject, ISequencedObject
{
private double _speed;
private string _CTRL;
private double _destination;
private double _duration;
private int _seqNb;
public string CTRL
{
get => _CTRL;
set
{
_CTRL = value;
OnPropertyChanged("CTRL");
}
}
public double Destination
{
get => _destination;
set
{
_destination = value;
OnPropertyChanged("Destination");
}
}
public double Speed
{
get => _speed;
set
{
_speed = value;
OnPropertyChanged("Speed");
}
}
public double Duration
{
get => _duration;
set
{
_duration = value;
OnPropertyChanged("Duration");
}
}
public int SequenceNumber
{
get => _seqNb;
set
{
_seqNb = value;
OnPropertyChanged("SequenceNumber");
}
}
//THIS EMPETY CONSTRUCTOR IS REALLY IMPORTANT. IT ALLOWS THE DISPLAY OF THE EMPTY ROW AT THE END OF THE DATAGRID
public DoliInput(){ }
public DoliInput(string CTRL, double destination, double speed, double duration)
{
this._CTRL = CTRL;
this._destination = destination;
this._speed = speed;
this._duration = duration;
}
}
GridDataVM
namespace InteractiveGraph.Grid
{
public class DataGridVM : ViewModelBase
{
void OnDoliCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Update item count
this.ItemCount = this.DoliInputCollection.Count;
// Resequence list
SetCollectionSequence(this.DoliInputCollection);
}
private ObservableCollection<DoliInput> _doliInputCollection;
private int _itemCount;
public DataGridVM()
{
this.Initialise();
}
public ObservableCollection<DoliInput> DoliInputCollection
{
get => _doliInputCollection;
set
{
_doliInputCollection = value;
OnPropertyChanged("DoliInputCollection");
}
}
public int ItemCount
{
get => _itemCount;
set
{
_itemCount = value;
OnPropertyChanged("ItemCount");
}
}
/// <summary>
/// Return selected item in the grid
/// </summary>
public DoliInput SelectedItem { get; set; }
/// <summary>
/// Resets the sequential order of a collection.
/// </summary>
/// <param name="targetCollection">The collection to be re-indexed.</param>
public static ObservableCollection<T> SetCollectionSequence<T>(ObservableCollection<T> targetCollection) where T : ISequencedObject
{
// Initialize
var sequenceNumber = 1;
// Resequence
foreach (ISequencedObject sequencedObject in targetCollection)
{
sequencedObject.SequenceNumber = sequenceNumber;
sequenceNumber++;
}
// Set return value
return targetCollection;
}
private void Initialise()
{
//Create inputList
_doliInputCollection = new ObservableCollection<DoliInput>();
//Add items
_doliInputCollection.Add(new DoliInput("Load", 3, 2, 1));
_doliInputCollection.Add(new DoliInput("Position", 3, 11, 1));
_doliInputCollection.Add(new DoliInput("Position", 3, 2, 4));
_doliInputCollection.Add(new DoliInput("Load", 3, 2, 1));
//Subscribe to the event that gets trigger when change occurs
_doliInputCollection.CollectionChanged += OnDoliCollectionChanged;
//Start indexing items
this.DoliInputCollection = SetCollectionSequence(this.DoliInputCollection);
//Update if changes
this.OnPropertyChanged("DoliInputCollection");
this.OnPropertyChanged("GridParam");
}
}
}
Файл xaml
<Window x:Class="InteractiveGraph.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:InteractiveGraph"
xmlns:dataGrid="clr-namespace:InteractiveGraph.Grid"
xmlns:vc="clr-namespace:InteractiveGraph.BugFix"
mc:Ignorable="d"
Title="MainWindow" Height="502.869" Width="935.246" SizeChanged="Window_SizeChanged">
<Window.DataContext>
<dataGrid:DataGridVM />
</Window.DataContext>
<Grid Background="LightGreen">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid>
<DataGrid Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Center" Height="100" Margin="0"
VerticalAlignment="Center" Width="522"
ItemsSource="{Binding DoliInputCollection}" AllowDrop="True" SelectionMode="Extended"
SelectedItem="{Binding SelectedItem}"
AutoGenerateColumns="False" ColumnWidth="*"
Name="inputlist"
CanUserSortColumns="False"
CanUserAddRows="True"
DataContextChanged="OnMainGridDataContextChanged"
RowEditEnding="inputlist_RowEditEnding">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Ctrl type">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding CbItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
SelectedValue="{Binding CTRL, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Destination, Mode=TwoWay}" Header="Destination" />
<DataGridTextColumn Binding="{Binding Speed, Mode=TwoWay}" Header="Speed" />
<DataGridTextColumn Binding="{Binding Duration, Mode=TwoWay}" Header="Duration(s)" >
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
</Window>
Код (он должен быть пустым, я знаю .. ..)
public partial class MainWindow : Window
{
public List<string> CbItem { get; set; }
public MainWindow()
{
InitializeComponent();
CbItem = new List<string> { "Position", "Load" };
}
//To be removed, trying to understand what is going wrong
private void inputlist_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
Console.WriteLine("######COUNT " + _viewModel.DoliInputCollection.Count().ToString());
foreach (var item in _viewModel.DoliInputCollection)
{
Console.WriteLine("CTRL = " + item.CTRL + ", destination = " + item.Destination.ToString() + ", SeqNum = " + item.SequenceNumber.ToString());
}
}
}
namespace InteractiveGraph.Utility
{
public abstract class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Protected Methods
/// <summary>
/// Fires the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this, e);
}
}
#endregion
}
}
ISequenceObject
namespace InteractiveGraph.Utility
{
/// <summary>
/// An object that can be given a sequential order in a collection.
/// </summary>
public interface ISequencedObject
{
/// <summary>
/// The sequence number of the object
/// </summary>
int SequenceNumber { get; set; }
}
}
ObservaleObject
namespace InteractiveGraph.Utility
{
public class ObservableObject : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Protected Methods
/// <summary>
/// Raises the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the property that was changed.</param>
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
var e = new PropertyChangedEventArgs(propertyName);
PropertyChanged(this, e);
}
}
#endregion
}
}