【发布时间】:2016-04-17 12:57:14
【问题描述】:
说明
我正在尝试构建这个简单的 UWP MVVM 笔记应用程序。
该应用程序的目的是将文本从 Textbox 添加到 ListView,当单击 Add Button 或删除 @987654325 的项目时@ 通过按 Delete Button,分配给ListView 中的每个项目。
将项目添加到 ObservableCollection
向ObservableCollection<Note> 添加项目似乎工作正常。项目显示在ListView 没有任何问题。
删除 ObservableCollection 中的项目
删除项目无法正常工作。
我的调试尝试
我尝试调用负责从构造函数和 Delete Button 中删除项目的方法。
当我从 Delete Button 调用 DoDeleteNote(Note itemToDelete) 时,什么也没有发生,但如果我从构造函数调用相同的方法,则该项目将被删除。
我在DoDeleteNote(Note itemToDelete) 方法中创建了一个断点,我可以在调试器中看到它在代码中运行,但没有从ObservableCollection<Note> 中删除任何内容。
但是,当我从构造函数调用 DoDeleteNote(Note itemToDelete) 方法时,该项目被删除。
奇怪的是,我从 NoteViewModel 构造函数创建并添加到 ObservableCollection<Note> 的 Note 项是 ObservableCollection<Note> 中的唯一项.我使用 Add Button 添加的项目已消失,但仍显示在 ListView 中。
我在想INotifyPropertyChanged 或绑定可能有问题,但我不确定从哪里开始寻找,以及寻找什么,所以我可以寻求帮助。
我知道这里似乎有很多代码,但我觉得有必要不要遗漏任何东西来理解数据流。
XAML
<Page
x:Class="ListView2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ListView2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModel="using:ListView2.ViewModel"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.DataContext>
<viewModel:NoteViewModel/>
</Grid.DataContext>
<ListView Header="Notes"
HorizontalAlignment="Left"
Height="341"
Width="228"
VerticalAlignment="Top"
Margin="163,208,0,0"
ItemsSource="{Binding Notes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.ItemTemplate>
<DataTemplate x:Name="MyDataTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TbxblListItem" Text="{Binding NoteText}"/>
<Button Command="{Binding DeleteNoteCommand}"
CommandParameter="{Binding ElementName=TbxblListItem}">
<Button.DataContext>
<viewModel:NoteViewModel/>
</Button.DataContext>
<Button.Content>
<SymbolIcon Symbol="Delete"
ToolTipService.ToolTip="Delete Note"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Button.Content>
</Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBox x:Name="TbxNoteContent" HorizontalAlignment="Left"
Margin="571,147,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="376"/>
<Button Content="Add"
HorizontalAlignment="Left"
Margin="597,249,0,0"
VerticalAlignment="Top"
Command="{Binding AddNoteCommand}"
CommandParameter="{Binding Text, ElementName=TbxNoteContent}"/>
</Grid>
</page>
注意
namespace ListView2.Model
{
class Note
{
private string _noteText;
public Note(string noteText)
{
NoteText = noteText;
}
public string NoteText { get { return _noteText; } set { _noteText = value; } }
}
}
通知
using System.ComponentModel;
namespace ListView2.Model
{
class Notification : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
NoteViewModel
using System.Collections.ObjectModel;
using Windows.UI.Xaml.Controls;
using ListView2.Model;
namespace ListView2.ViewModel
{
class NoteViewModel : Notification
{
#region Instance Fields
private ObservableCollection<Note> _notes;
private RelayCommand _addNoteCommand;
private RelayCommand _deleteNoteCommand;
//private string _noteText;
#endregion
#region Constructors
public NoteViewModel()
{
//adds sample data to Notes property (ObservableCollection<Note>)
Notes = new ObservableCollection<Note>() { new Note("Sample text 1"), new Note("Sample text 2") };
//Used for testing the deletion of items from ObservableCollection-------------------------------------
Notes.RemoveAt(1);
Notes.Add(new Note("Sample text 3"));
//foreach (var item in Notes)
//{
// if (item.NoteText == "Sample text 3")
// {
// DoDeleteNote(item);
// break;
// }
//}
//------------------------------------------------------
//Button command methods are added to delegates
AddNoteCommand = new RelayCommand(DoAddNote);
DeleteNoteCommand = new RelayCommand(DoDeleteNote);
}
#endregion
#region Properties
public ObservableCollection<Note> Notes { get { return _notes; } set { _notes = value; OnPropertyChanged("Notes"); } }
//public string NoteText { get { return _noteText; } set { _noteText = value; OnPropertyChanged("NoteText"); } }
public RelayCommand AddNoteCommand { get { return _addNoteCommand; } set { _addNoteCommand = value; } }
public RelayCommand DeleteNoteCommand { get { return _deleteNoteCommand; } set { _deleteNoteCommand = value; } }
#endregion
#region methods
private void DoAddNote(object obj)
{
var newItem = obj as string;
if (!string.IsNullOrEmpty(newItem))
{
AddNote(newItem);
}
}
//Work in progress
private void DoDeleteNote(object obj)
{
//Used when the XAML Delete Button invokes this method
TextBlock textBlockSender = obj as TextBlock;
//string myString = textBlockSender.Text;
Note itemToDelete = textBlockSender.DataContext as Note;
//Used when the constuctor invokes this method, for testing purposes------------
//Note itemToDelete = obj as Note;
//--------------------------------------------------------
foreach (Note note in this.Notes)
{
if (note.NoteText == itemToDelete.NoteText)
{
//int noteIndex = Notes.IndexOf(note);
//Notes.RemoveAt(noteIndex);
DeleteNote(note);
break;
}
}
//if (Notes.Contains(itemToDelete))
//{
// Notes.Remove(itemToDelete);
//}
}
public void AddNote(string noteText)
{
this.Notes.Add(new Note(noteText));
}
public void DeleteNote(Note itemToDelete)
{
this.Notes.Remove(itemToDelete);
}
#endregion
}
}
作为 ICommand 实现的 RelayCommand 类似乎与问题无关,所以我没有在此处包含它,但如果您好奇,可以在 GitHub 上看到它
【问题讨论】:
-
您确定在您的
Note itemToDelete = textBlockSender.DataContext as Note;中获得itemToDelete吗?如果你得到它,那么你确定它是Notes-this.Notes.Contains(note)中的注释吗? -
我刚刚再次尝试调试,该项目确实被删除,从
DoDeleteNote()方法中的ObservableCollection<Note>,但它似乎是创建的 2 个 Note 对象每次我通过DoAddNote()或DoDeleteNote()时都会重新创建构造函数中的内容,就像 ObservableCollection 已被重置一样。 Xaml 代码是否以某种方式多次实例化 NoteViewModel,所以ObservableCollection<Note>被重置?我认为可能与删除按钮中的 DataContext 有关,但我不太确定。 -
我刚刚注意到 `
` 这实际上是为每个实际创建 一个新的 NoteViewModel集合中的视图模型。而NoteViewModel显然不在this.Notes集合中。实际项目将自动传播到 DataTemplate 的 DataContext - 无需执行任何特殊操作。 -
我将
<DataContext>添加到<Button>,以便能够将<Button Command >绑定到DeleteNoteCommand,因为ListView ItemsSource指向注释 ,所以<TextBox>可以使用Note 属性,而<Button>只能绑定到与<TextBox>相同的项目,因为它们在同一个<ListView>内。我不确定如何解决这个问题,因为 MVVM 和 XAML 对我来说是新的,但似乎我们找到了罪魁祸首。
标签: c# xaml listview win-universal-app observablecollection