0

编辑:正如评论所建议的,我应该实现 MVVM 模式,我已经做到了。然而,同样的问题仍然存在。所以我相应地改变了这个问题:

我有一个数据网格,其中包含绑定到可观察集合的两列(在 MyNotes 类中)。一列包含一个组合框,另一列包含一个文本框。该集合存储对包含枚举变量(由组合框显示)和字符串(由文本框显示)的 Note 对象的引用。除了 SelectedItems(以及 SelectedItem)之外,一切正常。当程序构建并运行时,您可以向数据网格添加新行(使用添加/删除按钮),但在尝试编辑(通过输入数据网格的文本框或组合框)后,数据网格的 selectedItems 和 selectedItem 将失败。这可以通过使用添加/删除按钮看到:选择的行没有被删除,新的行没有分别添加到选择的行上方。这是有关 SelectedNote 属性失去其绑定的症状的结果(我不知道为什么会发生这种情况,当我尝试破解重新绑定时,重新绑定失败?)。另一个症状与所选项目属性有关,它没有反映数据网格实际显示为选中的内容(在调试模式下查看时)。

我确信这个问题与数据网格的问题有关,这使得它无法用于我的案例。

这是新的 XAML(它的数据上下文视图模型在 XAML 中设置,ParaTypes 和 headerText 都是 XAML 静态资源):

<DataGrid x:Name                  ="dgdNoteLimits"
              ItemsSource             ="{Binding ParagraphCollection}"
              SelectedItem            ="{Binding Path=SelectedNote, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
              AllowDrop               ="True"
              HeadersVisibility       ="Column"
              AutoGenerateColumns     ="False"
              CanUserAddRows          ="False"
              CanUserReorderColumns   ="False"
              CanUserSortColumns      ="False"
              BorderThickness         ="0"
              VerticalGridLinesBrush  ="DarkGray"
              HorizontalGridLinesBrush="DarkGray"
              SelectionMode           ="Extended"
              SelectionUnit           ="FullRow"
              ColumnHeaderStyle       ="{StaticResource headerText}">
        <DataGrid.ItemContainerStyle>
            <Style>
                <Style.Resources>
                    <!-- SelectedItem's background color when focused -->
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                                         Color="Blue"/>
                    <!-- SelectedItem's background color when NOT focused -->
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                                         Color="Blue" />
                </Style.Resources>
            </Style>
        </DataGrid.ItemContainerStyle>
        <DataGrid.Columns>
            <DataGridComboBoxColumn Header              = "Note Type"
                                    ItemsSource         = "{Binding Source={StaticResource ParaTypes}}"
                                    SelectedValueBinding= "{Binding Path=NoteType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                    TextBinding         = "{Binding Path=NoteType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                    MinWidth            = "115"
                                    Width               = "Auto">
            </DataGridComboBoxColumn>
            <DataGridTextColumn Header ="Description"
                                Binding="{Binding Path=NoteText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                Width  ="*">
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="TextWrapping"
                                Value   ="Wrap"/>
                    </Style>
                </DataGridTextColumn.ElementStyle>
                <DataGridTextColumn.EditingElementStyle>
                    <Style TargetType="TextBox">
                        <Setter Property="SpellCheck.IsEnabled"
                                Value   ="true" />
                        <Setter Property="TextWrapping"
                                Value   ="Wrap"/>
                    </Style>
                </DataGridTextColumn.EditingElementStyle>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
    <StackPanel Grid.Row="1"
                Margin="0, 0, 0, 16"
                Orientation="Horizontal"
                HorizontalAlignment="Right">
        <Button Content="Add"
                Width="72"
                Margin="16,8,8,8"
                Command="{Binding AddClickCommand}"/>
        <Button Content="Remove"
                Width="72"
                Margin="16,8,8,8"
                Command="{Binding RemoveClickCommand}"/>
    </StackPanel>

这是视图模型:

class MainWindowViewModel : INotifyPropertyChanged
{
    MyNotes NotesCollection;
    private bool canExecute;
    private ICommand clickCommand;

    public MainWindowViewModel()
    {
        this.NotesCollection = new MyNotes();
        this.ParagraphCollection = this.NotesCollection.Notes;
        this.canExecute = true;
    }

    private ObservableCollection<Note> paragraphCollection;
    public ObservableCollection<Note> ParagraphCollection
    {
        get { return this.paragraphCollection; }
        set
        {
            this.paragraphCollection = value;
            RaisePropertyChanged(() => this.ParagraphCollection);
        }
    }

    private Note selectedNote;
    public Note SelectedNote
    {
        get { return this.selectedNote; }
        set
        {
            if (this.selectedNote == value)
                return;

            this.selectedNote = value;
            RaisePropertyChanged(() => this.SelectedNote);
        }
    }

    public ICommand AddClickCommand
    {
        get
        {
            return this.clickCommand ?? (new ClickCommand(() => AddButtonHandler(), canExecute));
        }
    }
    public void AddButtonHandler()
    {
        int noteIndex = 0;
        Note aNote;

        // what to do if a note is either selected or unselected...
        if (this.SelectedNote != null)
        {
            // if a row is selected then add row above it.
            if (this.SelectedNote.NoteIndex != null)
                noteIndex = (int)this.SelectedNote.NoteIndex;
            else
                noteIndex = 0;

            //create note and insert it into collection.
            aNote = new Note(noteIndex);
            ParagraphCollection.Insert(noteIndex, aNote);

            // Note index gives sequential order of collection
            // (this allows two row entries to have same NoteType
            // and NoteText values but still note equate).
            int counter = noteIndex;
            // reset collection index so they are sequential
            for (int i = noteIndex; i < this.NotesCollection.Notes.Count; i++)
            {
                this.NotesCollection.Notes[i].NoteIndex = counter++;
            }
        }
        else
        {
            //if a row is not selected add it to the bottom.
            aNote = new Note(this.NotesCollection.Count);
            this.ParagraphCollection.Add(aNote);
        }
    }

    public ICommand RemoveClickCommand
    {
        get
        {
            return this.clickCommand ?? (new ClickCommand(() => RemoveButtonHandler(), canExecute));
        }
    }
    public void RemoveButtonHandler()
    {
        //delete selected note.
        this.ParagraphCollection.Remove(selectedNote);
    }

    //boiler plate INotifyPropertyChanged implementation!
    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged<T>(Expression<System.Func<T>> propertyExpression)
    {
        var memberExpr = propertyExpression.Body as MemberExpression;
        if (memberExpr == null)
            throw new ArgumentException("propertyExpression should represent access to a member");
        string memberName = memberExpr.Member.Name;
        RaisePropertyChanged(memberName);
    }
    protected virtual void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

和模型:

class MyNotes
{
    public ObservableCollection<Note> Notes;

    public MyNotes()
    {
        this.Notes = new ObservableCollection<Note>();
    }
}

public enum NoteTypes
{
    Header, Limitation, Warning, Caution, Note
}

public class Note
{
    public int?      NoteIndex { get; set; }
    public NoteTypes NoteType  { get; set; }
    public string    NoteText  { get; set; }

    public Note()
    {
        this.NoteIndex = null;
        this.NoteType = NoteTypes.Note;
        this.NoteText = "";
    }
    public Note(int? noteIndex): this()
    {
        this.NoteIndex = noteIndex;
    }

    public override string ToString()
    {
        return this.NoteType + ": " + this.NoteText;
    }
    public override bool Equals(object obj)
    {
        Note other = obj as Note;

        if (other == null)
            return false;
        if (this.NoteIndex != other.NoteIndex)
            return false;
        if (this.NoteType != other.NoteType)
            return false;
        if (this.NoteText != other.NoteText)
            return false;

        return true;
    }
    public override int GetHashCode()
    {
        int hash = 17;

        hash = hash * 23 + this.NoteIndex.GetHashCode();
        hash = hash * 23 + this.NoteType.GetHashCode();
        hash = hash * 23 + this.NoteText.GetHashCode();

        return hash;
    }
}

非常感谢现有的评论(我学到了很多东西并看到了 MVVM 的价值)。可惜他们没有解决问题。不过谢谢。

因此,如果有人知道我如何解决这个问题,那将不胜感激。

4

0 回答 0