问题
Hi please could somebody help? I have a ListView which is bound to a ObservableCollection i.e StabCollection. The data displays perfectly.
I have a couple of textboxes and a combo box to enable the user to edit the columns. When those textboxes are edited the values change in the gridview as expected however I am trying to achieve a cancel feature to revert changes back to the original. Manually changing the SelectedItem of StabCollection or changing the StabCollection[SelectedIndex] doesn't update the UI however the collection is changing. Any help will be appreciated.
<Window.DataContext>
<local:MoveStabViewModel/>
</Window.DataContext>
<StackPanel>
<Menu IsEnabled="{Binding ListViewEnabled}">
<MenuItem Header="File"/>
<MenuItem Header="Add" Command="{Binding AddCommand}"/>
<MenuItem Header="Delete"/>
</Menu>
<StackPanel Orientation="Horizontal">
<ListView ItemsSource="{Binding StabCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding ListViewEnabled}" SelectedIndex="{Binding SelectedIndex}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="10" >
<ListView.Resources>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
<Style TargetType="GridViewColumnHeader">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Padding" Value="5"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Position}" Width="Auto" Header="Position (m)"/>
<GridViewColumn DisplayMemberBinding="{Binding Type}" Width="Auto" Header="Type"/>
<GridViewColumn DisplayMemberBinding="{Binding Pot}" Width="Auto" Header="Tip (mV)"/>
<GridViewColumn DisplayMemberBinding="{Binding Current}" Width="Auto" Header="Current (mA)"/>
<GridViewColumn DisplayMemberBinding="{Binding CurrentDensity}" Width="Auto" Header="Current Density (mA/m2)"/>
<GridViewColumn DisplayMemberBinding="{Binding FieldGradient}" Width="Auto" Header="Field Gradient (uV/cm)"/>
</GridView>
</ListView.View>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding EditCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
<GroupBox Header="Edit Stabs" Width="Auto" Visibility="{Binding IsEdit, Converter={StaticResource BoolToVisConverter }}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Content="Position" Grid.Column="0" Grid.Row="0"/>
<Label Content="Contact Type" Grid.Column="0" Grid.Row="1"/>
<Label Content="Potential" Grid.Column="0" Grid.Row="3"/>
<TextBox Text="{Binding SelectedItem.Position, Mode=TwoWay}" Grid.Row="0" Grid.Column="1"/>
<ComboBox x:Name="PrintOutComboBox" ItemsSource="{Binding PrintOut}" Width="220" SelectedItem="{Binding SelectedItem.Type, Mode=TwoWay}"
Grid.Row="1" Grid.Column="1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding ButtonOneCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<ComboBox SelectedIndex="{Binding ElementName=PrintOutComboBox, Path=SelectedIndex}" Width="{Binding ElementName=PrintOutComboBox ,Path=Width}"
ItemsSource="{Binding LongPrintOut}" Grid.Row="2" Grid.Column="1"/>
<TextBox Text="{Binding SelectedItem.Pot, Mode=TwoWay}" Grid.Row="3" Grid.Column="1"/>
<UniformGrid Grid.Row="4" Grid.ColumnSpan="2" Columns="2">
<Button Content="{Binding ButtonOne}" Command="{Binding ButtonOneCommand}"/>
<Button Content="Cancel" Command="{Binding CancelCommand}"/>
</UniformGrid>
</Grid>
</GroupBox>
</StackPanel>
</StackPanel>
public class MoveStabViewModel : INotifyPropertyChanged, IDialogRequestClose
{
ChartEditViewModel VM;
List<AnnotationFile> annotation;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string[] _printOut;
public string[] PrintOut
{
get { return _printOut; }
set { _printOut = value; }
}
string[] _longPrintOut;
public string[] LongPrintOut
{
get { return _longPrintOut; }
set { _longPrintOut = value; }
}
private string[] SplitCommaDelimitedString(string value)
{
string[] splitString = value.Split(',');
return splitString;
}
ObservableCollection<StabTypes> stabTypes;
public ObservableCollection<StabTypes> StabTypes { get { return stabTypes; } }
public MoveStabViewModel()
{
}
public MoveStabViewModel(ChartEditViewModel VM)
{
this.VM = VM;
annotation = VM.annotation;
PrintOut = new string[21];
LongPrintOut = new string[21];
stabTypes = new ObservableCollection<StabTypes>();
for (int i = 0; i < 20; i++)
{
PrintOut[i] = VM.printOut[i + 1];
LongPrintOut[i] = VM.printLongName[i + 1];
stabTypes.Add(new StabTypes { Code = PrintOut[i], Description = LongPrintOut[i] });
}
EditCommand = new ActionCommand(p => LstContactsDoubleClick());
CancelCommand = new ActionCommand(p => Cancel());
ButtonOneCommand = new ActionCommand(p => ButtonOneMethod());
AddCommand = new ActionCommand(p => Add());
LoadStabs();
}
private void ButtonOneMethod()
{
if (ButtonOne == "Add Stab")
{
}
else
{
//StabCollection[SelectedIndex].Position = SelectedItem.Position;
//StabCollection[SelectedIndex].Pot = SelectedItem.Pot;
//StabCollection[SelectedIndex].Type = DisplayStab;
}
}
private void Add()
{
SelectedItem = null;
DisplayStab = "";
ListViewEnabled = false;
if (SelectedItem != null)
{
DisplayStab = SelectedItem.Type;
}
else
{
DisplayStab = "";
}
ButtonOne = "Add Stab";
WindowSize += 342;
}
public List<string[]> TempAnno { get; set; }
private ObservableCollection<AnnotationBreakDown> _stabBreakdown = new ObservableCollection<AnnotationBreakDown>();
public ObservableCollection<AnnotationBreakDown> StabCollection
{
get { return _stabBreakdown;}
set { _stabBreakdown = value; OnPropertyChanged("StabCollection"); }
}
public ICommand EditCommand { get; }
public ICommand CancelCommand { get; }
public ICommand AddCommand { get; }
public ICommand ButtonOneCommand { get; }
public event EventHandler<DialogCloseRequestedEventArgs> CloseRequested;
public event PropertyChangedEventHandler PropertyChanged;
public void LoadStabs()
{
var annotationFile = new AnnotationFile();
int j = 0;
for (int i = 0; i < annotation.Count; i++)
{
if (annotation[i]._type == "E")
{
var tempStringArray = SplitCommaDelimitedString(annotation[i]._anno);
int stabType = annotationFile.EvalStabType(Strings.Mid(annotation[i]._anno, 1, 1));
bool potCorrectFormat = float.TryParse(tempStringArray[0].Substring(1, 5), out float pot);
bool currentCorrectFormat = float.TryParse(tempStringArray[1], out float current);
bool cdCorrectFormat = float.TryParse(tempStringArray[2], out float cd);
bool fgCorrectFormat = float.TryParse(tempStringArray[3], out float fg);
bool mcCorrectFormat = float.TryParse(tempStringArray[4], out float mc); //McCoy Current
bool mcCDCorrectFormat = float.TryParse(tempStringArray[5], out float mcd);
bool mcFGCorrectFormat = float.TryParse(tempStringArray[6], out float mfg);
StabCollection.Add(new AnnotationBreakDown());
StabCollection[j].Position = Strings.Format(annotation[i]._KP, "#####0.0");
StabCollection[j].Type = VM.printOut[stabType];
if (potCorrectFormat) StabCollection[j].Pot = pot;
if (currentCorrectFormat) StabCollection[j].Current = current;
if (cdCorrectFormat) StabCollection[j].CurrentDensity = cd;
if (fgCorrectFormat) StabCollection[j].FieldGradient = fg;
if (mcCorrectFormat) StabCollection[j].MC = mc;
if (mcCDCorrectFormat) StabCollection[j].MCD = mcd;
if (mcFGCorrectFormat) StabCollection[j].MFG = mfg;
j += 1;
}
}
}
//Are we editing the stabs?
private bool _listviewEnabled = true;
public bool ListViewEnabled
{
get { return _listviewEnabled; }
set { _listviewEnabled = value; OnPropertyChanged("ListViewEnabled"); }
}
//The selected item from listview
private AnnotationBreakDown _selectedItem = new AnnotationBreakDown();
public AnnotationBreakDown SelectedItem
{
get { return _selectedItem; }
set { _selectedItem = value; OnPropertyChanged("SelectedItem"); }
}
private string _displayStab;
public string DisplayStab
{
get { return _displayStab; }
set { _displayStab = value; OnPropertyChanged("DisplayStab"); }
}
//The listview Selected Index
int _selectedIndex;
public int SelectedIndex
{
get { return _selectedIndex; }
set { _selectedIndex = value; OnPropertyChanged("SelectedIndex"); }
}
//Property to store Add/Accept Button
private string _buttonOne = "Accept";
public string ButtonOne
{
get { return _buttonOne; }
set { _buttonOne = value; OnPropertyChanged("ButtonOne"); }
}
string tempPos;
string tempType;
float tempPot;
//Event called when mouse is double clicked on listview
public void LstContactsDoubleClick()
{
if (SelectedItem == null) return;
tempPos = StabCollection[SelectedIndex].Position;
tempType = StabCollection[SelectedIndex].Type;
tempPot = StabCollection[SelectedIndex].Pot;
ListViewEnabled = false;
DisplayStab = SelectedItem.Type;
WindowSize += 342;
}
//Dynamic Window Size CLR property
private int _windowSize = 610;
public int WindowSize
{
get { return _windowSize; }
set { _windowSize = value; OnPropertyChanged("WindowSize"); }
}
public void Cancel()
{
ListViewEnabled = true;
SelectedItem.Type = "GP";
WindowSize -= 342;
}
}
public class StabTypes
{
public string Code { get; set; }
public string Description { get; set; }
public string CodeToolTip
{
get { return Description; }
}
}
public class AnnotationBreakDown
{
public string Position { get; set; }
public string Type { get; set;}
public float Pot { get; set; }
public float Current { get; set; }
public float CurrentDensity { get; set; }
public float FieldGradient { get; set; }
public float MC { get; set; } //McCoy Current
public float MCD { get; set;} //McCoy CD
public float MFG { get; set; } //McCoy FG
}
}
回答1:
Because ObservableCollection
doesn't observe his items. It will raise an event for an insert, delete an item, or reset the collection, not a modification on his item.
So, you must implement ObservableCollection
which observe equally his items. This code used in my project found on SO but I can't figure out the post original.
public class ItemsChangeObservableCollection<T> :
System.Collections.ObjectModel.ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
RegisterPropertyChanged(e.NewItems);
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
UnRegisterPropertyChanged(e.OldItems);
}
else if (e.Action == NotifyCollectionChangedAction.Replace)
{
UnRegisterPropertyChanged(e.OldItems);
RegisterPropertyChanged(e.NewItems);
}
base.OnCollectionChanged(e);
}
protected override void ClearItems()
{
UnRegisterPropertyChanged(this);
base.ClearItems();
}
private void RegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
if (item != null)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
private void UnRegisterPropertyChanged(IList items)
{
foreach (INotifyPropertyChanged item in items)
{
if (item != null)
{
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
}
}
}
private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//launch an event Reset with name of property changed
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
}
private ItemsChangeObservableCollection<AnnotationBreakDown> _stabBreakdown = new ItemsChangeObservableCollection<AnnotationBreakDown>();
public ItemsChangeObservableCollection<AnnotationBreakDown> StabCollection
{
get { return _stabBreakdown;}
set { _stabBreakdown = value; }
}
Last but not least, your model must implement INotifyPropertyChanged
public class AnnotationBreakDown : INotifyPropertyChanged
{
public string Position { get; set; } // To raise PropertyChanged
public string Type { get; set;} // To raise PropertyChanged
public float Pot { get; set; } // To raise PropertyChanged
public float Current { get; set; } // To raise PropertyChanged
public float CurrentDensity { get; set; } // To raise PropertyChanged
public float FieldGradient { get; set; } // To raise PropertyChanged
public float MC { get; set; } //McCoy Current
public float MCD { get; set;} //McCoy CD
public float MFG { get; set; } //McCoy FG
}
来源:https://stackoverflow.com/questions/51288331/observablecollection-not-updating-my-gridviewcolumns-mvvm