当可观察集合发生变化时,列表视图不会得到更新
The listview don't get update when the observable collection changes
这是列表视图
<ListView x:Name="task_list" SelectionChanged="task_list_SelectionChanged" Grid.Row="0" Grid.Column="1" Background="Transparent">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TaskTodo">
<TextBlock Width="100" Foreground="White" Text="{x:Bind NameTask}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
和视图模型
public class TaskTodo : INotifyPropertyChanged
{
private string _NameTask, _Reminder, _Date, _Priority, _NameList, _Description;
private int _Id, _ParentTask;
private DateTimeOffset _NextRep;
public TaskTodo()
{
_NameTask = String.Empty;
_Reminder = String.Empty;
_Date = String.Empty;
_Priority = String.Empty;
_NameList = String.Empty;
_Description = String.Empty;
_ParentTask = -1;
_Id = 1;
}
Resource_Manager rm = new Resource_Manager();
public event PropertyChangedEventHandler PropertyChanged;
TaskSqliteDataAccess TaskSqlite = new TaskSqliteDataAccess();
private void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public int TaskId { get { return _Id; } set { _Id = value; NotifyPropertyChanged(TaskId.ToString()); } }
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(NameTask); } }
public string Reminder { get { return _Reminder; } set { _Reminder = value; NotifyPropertyChanged(FormatDateReminder); } }
public string NameList {
get
{
if ( _NameList == string.Empty || _NameList == null)
{
return rm.GetDefaultNamelist;
}
return _NameList;
}
set { _NameList = value; NotifyPropertyChanged(NameList); }
}
public string Date { get { return _Date ; } set { _Date = value; NotifyPropertyChanged(FormatDate); } }
public string FormatDate
{
get
{
var cultureInfo = new CultureInfo("en-US");
DateTimeOffset DueDate;
if (Date != string.Empty && Date != null)
{
DueDate = DateTimeOffset.Parse(Date, cultureInfo);
return String.Format(" {0},{1} {2}", DueDate.DayOfWeek, DueDate.Day, DueDate.ToString("MMM"));
}
else
return rm.GetDefaultDate;
}
}
public string Priority { get { return _Priority; } set { _Priority = value; NotifyPropertyChanged(Priority); } }
public string Description { get { return _Description; } set { _Description = value; NotifyPropertyChanged(Description); } }
public DateTimeOffset NextRep { get { return _NextRep; } set { _NextRep= value; NotifyPropertyChanged(NextRep.ToString()); } }
public int ParentTask { get { return _ParentTask; } set { _ParentTask = value; NotifyPropertyChanged(TaskId.ToString()); } }
public string FormatTimeReminder
{
get {
DateTime Time;
var cultureInfo = new CultureInfo("en-US");
if ( Reminder != string.Empty && Reminder != null )
{
Time = DateTime.Parse (Reminder, cultureInfo);
return string.Format(" Remind me at {0}:{1}", Time.Hour, Time.Minute);
}
return rm.GetDefaultReminder;
}
}
public string FormatDateReminder
{
get
{
DateTimeOffset Date;
if(DateTimeOffset.TryParse(_Reminder, out Date) == true)
{
return string.Format(" {0},{1} {2}", Date.DayOfWeek, Date.Day, Date.ToString("MMM"));
}
return Reminder;
}
}
public ObservableCollection<TaskTodo> GetTasks() => TaskSqlite.GetTaskDB();
public void AddTask(TaskTodo task) => TaskSqlite.AddTaskDB(task);
public void UpdateTask() => TaskSqlite.UpdateData(TaskId, NameTask, Date, Reminder, Priority, NameList, Description, NextRep);
public ObservableCollection<TaskTodo> GetSubtasks(TaskTodo taskTodo) => TaskSqlite.GetSubtasks(taskTodo);
例如,如果我更改表单中的 NameTask 属性,属性 会更改,并且如果将 属性 绑定到表单中的 texblock,texblock 将具有新的值,但列表视图的 texblock 没有
StackPanel Name="TaskForm" Grid.Column="2" Width="340" Background="#04000E" HorizontalAlignment="Right" Visibility="Collapsed" >
<Button FontSize="20" Name="quit_TaskForm" Content="x" Click="quit_TaskForm_Click" HorizontalAlignment="Right" Background="Transparent"></Button>
<TextBox Name="NameTaskForm" HorizontalAlignment="Center" FontSize="20"
TextChanged="NameTaskForm_TextChanged" LostFocus="NameTaskForm_LostFocus" Foreground="White"
DataContext="{Binding ElementName=task_list, Path=SelectedItem}"
Text="{Binding Path=NameTask, Mode=TwoWay}"
Style="{StaticResource TextBoxStyle1}" BorderThickness="0" />
</StackPanel>
这是表单文本框文本发生变化时的事件代码
private void NameTaskForm_TextChanged(object sender, TextChangedEventArgs e)
{
if ((task_list.SelectedItem as TaskTodo)!= null)
{
(task_list.SelectedItem as TaskTodo).NameTask = NameTaskForm.Text;
(task_list.SelectedItem as TaskTodo).UpdateTask();
}
}
NotifyPropertyChanged
方法采用 属性 的名称,而不是它的值 ...
NotifyPropertyChanged(NameTask);
这应该改为
NotifyPropertyChanged(nameof(NameTask));
如这一行
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(NameTask); } }
应该是这样的
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(nameof(NameTask)); } }
所以你必须在每次调用 NotifyPropertyChanged
时编辑所有代码,以给它你更改的 属性 的名称......或者你可以让编译器自动获取调用者 属性 名称只是使用 CallerMemberName
属性
using System.Runtime.CompilerServices;
//...
void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
并在不传递任何值的情况下调用它,编译器会自动获取调用者姓名
如下
public string NameTask
{
get { return _NameTask; }
set
{
_NameTask = value;
NotifyPropertyChanged(); // without passing any value
}
}
这是列表视图
<ListView x:Name="task_list" SelectionChanged="task_list_SelectionChanged" Grid.Row="0" Grid.Column="1" Background="Transparent">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:TaskTodo">
<TextBlock Width="100" Foreground="White" Text="{x:Bind NameTask}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
和视图模型
public class TaskTodo : INotifyPropertyChanged
{
private string _NameTask, _Reminder, _Date, _Priority, _NameList, _Description;
private int _Id, _ParentTask;
private DateTimeOffset _NextRep;
public TaskTodo()
{
_NameTask = String.Empty;
_Reminder = String.Empty;
_Date = String.Empty;
_Priority = String.Empty;
_NameList = String.Empty;
_Description = String.Empty;
_ParentTask = -1;
_Id = 1;
}
Resource_Manager rm = new Resource_Manager();
public event PropertyChangedEventHandler PropertyChanged;
TaskSqliteDataAccess TaskSqlite = new TaskSqliteDataAccess();
private void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public int TaskId { get { return _Id; } set { _Id = value; NotifyPropertyChanged(TaskId.ToString()); } }
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(NameTask); } }
public string Reminder { get { return _Reminder; } set { _Reminder = value; NotifyPropertyChanged(FormatDateReminder); } }
public string NameList {
get
{
if ( _NameList == string.Empty || _NameList == null)
{
return rm.GetDefaultNamelist;
}
return _NameList;
}
set { _NameList = value; NotifyPropertyChanged(NameList); }
}
public string Date { get { return _Date ; } set { _Date = value; NotifyPropertyChanged(FormatDate); } }
public string FormatDate
{
get
{
var cultureInfo = new CultureInfo("en-US");
DateTimeOffset DueDate;
if (Date != string.Empty && Date != null)
{
DueDate = DateTimeOffset.Parse(Date, cultureInfo);
return String.Format(" {0},{1} {2}", DueDate.DayOfWeek, DueDate.Day, DueDate.ToString("MMM"));
}
else
return rm.GetDefaultDate;
}
}
public string Priority { get { return _Priority; } set { _Priority = value; NotifyPropertyChanged(Priority); } }
public string Description { get { return _Description; } set { _Description = value; NotifyPropertyChanged(Description); } }
public DateTimeOffset NextRep { get { return _NextRep; } set { _NextRep= value; NotifyPropertyChanged(NextRep.ToString()); } }
public int ParentTask { get { return _ParentTask; } set { _ParentTask = value; NotifyPropertyChanged(TaskId.ToString()); } }
public string FormatTimeReminder
{
get {
DateTime Time;
var cultureInfo = new CultureInfo("en-US");
if ( Reminder != string.Empty && Reminder != null )
{
Time = DateTime.Parse (Reminder, cultureInfo);
return string.Format(" Remind me at {0}:{1}", Time.Hour, Time.Minute);
}
return rm.GetDefaultReminder;
}
}
public string FormatDateReminder
{
get
{
DateTimeOffset Date;
if(DateTimeOffset.TryParse(_Reminder, out Date) == true)
{
return string.Format(" {0},{1} {2}", Date.DayOfWeek, Date.Day, Date.ToString("MMM"));
}
return Reminder;
}
}
public ObservableCollection<TaskTodo> GetTasks() => TaskSqlite.GetTaskDB();
public void AddTask(TaskTodo task) => TaskSqlite.AddTaskDB(task);
public void UpdateTask() => TaskSqlite.UpdateData(TaskId, NameTask, Date, Reminder, Priority, NameList, Description, NextRep);
public ObservableCollection<TaskTodo> GetSubtasks(TaskTodo taskTodo) => TaskSqlite.GetSubtasks(taskTodo);
例如,如果我更改表单中的 NameTask 属性,属性 会更改,并且如果将 属性 绑定到表单中的 texblock,texblock 将具有新的值,但列表视图的 texblock 没有
StackPanel Name="TaskForm" Grid.Column="2" Width="340" Background="#04000E" HorizontalAlignment="Right" Visibility="Collapsed" >
<Button FontSize="20" Name="quit_TaskForm" Content="x" Click="quit_TaskForm_Click" HorizontalAlignment="Right" Background="Transparent"></Button>
<TextBox Name="NameTaskForm" HorizontalAlignment="Center" FontSize="20"
TextChanged="NameTaskForm_TextChanged" LostFocus="NameTaskForm_LostFocus" Foreground="White"
DataContext="{Binding ElementName=task_list, Path=SelectedItem}"
Text="{Binding Path=NameTask, Mode=TwoWay}"
Style="{StaticResource TextBoxStyle1}" BorderThickness="0" />
</StackPanel>
这是表单文本框文本发生变化时的事件代码
private void NameTaskForm_TextChanged(object sender, TextChangedEventArgs e)
{
if ((task_list.SelectedItem as TaskTodo)!= null)
{
(task_list.SelectedItem as TaskTodo).NameTask = NameTaskForm.Text;
(task_list.SelectedItem as TaskTodo).UpdateTask();
}
}
NotifyPropertyChanged
方法采用 属性 的名称,而不是它的值 ...
NotifyPropertyChanged(NameTask);
这应该改为
NotifyPropertyChanged(nameof(NameTask));
如这一行
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(NameTask); } }
应该是这样的
public string NameTask { get { return _NameTask; } set { _NameTask = value; NotifyPropertyChanged(nameof(NameTask)); } }
所以你必须在每次调用 NotifyPropertyChanged
时编辑所有代码,以给它你更改的 属性 的名称......或者你可以让编译器自动获取调用者 属性 名称只是使用 CallerMemberName
属性
using System.Runtime.CompilerServices;
//...
void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
并在不传递任何值的情况下调用它,编译器会自动获取调用者姓名
如下
public string NameTask
{
get { return _NameTask; }
set
{
_NameTask = value;
NotifyPropertyChanged(); // without passing any value
}
}