ObservableCollection 不更新我的 GridViewColumns (MVVM)

ObservableCollection not updating my GridViewColumns (MVVM)

嗨,有人能帮忙吗?我有一个绑定到 ObservableCollection 的 ListView,即 StabCollection。数据显示完美。

我有几个文本框和一个组合框,使用户能够编辑列。当编辑这些文本框时,gridview 中的值会按预期发生变化,但是我正在尝试实现取消功能以将更改恢复为原始状态。手动更改 StabCollection 的 SelectedItem 或更改 StabCollection[SelectedIndex] 不会更新 UI,但集合正在更改。任何帮助将不胜感激。

     <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
}

}

因为ObservableCollection不观察他的物品。它将引发插入事件、删除项目或重置集合,而不是修改他的项目。

因此,您必须实施 ObservableCollection 以同样地观察他的项目。在我的项目中使用的代码是在 SO 上找到的,但我无法弄清楚 post 原始代码。

    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; }
    }

最后但同样重要的是,您的模型必须实现 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
}