我有一个
DataGrid
,其中 ItemsSource
绑定到 DataTable
。当我更新 DataTable
时,来自 ViewModel
的数据会更新,但 UI 不会更新。我已经将 INotifyPropertyChanged
用于我的 ViewModel
。
这是我的功能
private DataTable hariKerjaTable;
public DataTable HariKerjaTable
{
get => hariKerjaTable;
set
{
hariKerjaTable = value;
OnPropertyChanged(nameof(HariKerjaTable));
}
}
private DataTable kalenderKerjaTable;
public DataTable KalenderKerjaTable
{
get => kalenderKerjaTable;
set
{
kalenderKerjaTable = value;
OnPropertyChanged(nameof(KalenderKerjaTable));
}
}
private async void GetWorkingCalendar()
{
HariKerjaTable.Clear();
KalenderKerjaTable.Columns.Clear();
KalenderKerjaTable.Rows.Clear();
var data = new
{
month = Month,
year = Year,
};
string get = await BaseAPI.PostMethod("calendar/select", JsonConvert.SerializeObject(data));
if (get is not null)
{
JObject jsonObject = JObject.Parse(get);
JToken dataToken = jsonObject["data"];
HariKerjaTable = dataToken.ToObject<DataTable>();
}
else
{
MessageBox.Show("Something wrong when retrieving", "Null", MessageBoxButton.OK, MessageBoxImage.Error);
}
Application.Current.Dispatcher.Invoke(() =>
{
foreach (DataRow row in HariKerjaTable.Rows)
{
DateTime date = DateTime.Parse(row["date_calendar"].ToString());
Debug.WriteLine(date.ToString("ddd\ndd"));
if (!KalenderKerjaTable.Columns.Contains(date.ToString("ddd\ndd")))
{
KalenderKerjaTable.Columns.Add(date.ToString("ddd\ndd"));
}
}
OnPropertyChanged(nameof(KalenderKerjaTable));
});
Debug.WriteLine("+++++++++++++++++++++++++++++++");
foreach (DataColumn column in KalenderKerjaTable.Columns)
{
Debug.WriteLine(column.ColumnName);
}
}
这是我的 XAML
<Grid Grid.Row="1" Margin="0,5,0,0">
<DataGrid ItemsSource="{Binding KalenderKerjaTable, Mode=TwoWay}" FrozenColumnCount="2" AutoGenerateColumns="True"/>
</Grid>
我尝试将
Mode=TwoWay
和 UpdateSourceTrigger=PropertyChanged
添加到 XAML,但它没有改变任何内容。
首先,我们永远不应该声明
async void
方法,因为它为许多不同的错误打开了大门。唯一的例外是事件处理程序。始终返回 Task
或 Task<TResult>
:
// Serious code smell
private async void GetWorkingCalendar();
// Correct signature
private async Task GetWorkingCalendarAsync();
接下来,
Dispatcher.Invoke
是多余的:DataTable不会扩展DispatcherObject
并且设置引发INotifyPropertyChanged.PropertyChnaged
的属性从来都不是问题,因为绑定引擎会将事件编组到正确的调度程序线程。
此外,您应该使用
System.Text.Json
API,因为它提供了异步 API:.NET 中的 JSON 序列化和反序列化(编组和解组) - 概述
TwoWay
绑定到 ItemsControl.ItemsSource
上没有任何意义,因为 ItemsControl
永远不会更改设置为 IEnumerable
属性的 ItemsSource
实例。ItemsSource
属性的绑定应该是 OneTime
。
解决您的主要问题,单独提高
PropertyChanged
没有帮助,因为实例仍然相同。仅当旧值和新值不是同一个实例时,绑定到属性的依赖属性才会更新自身。
您必须替换实例(保存
DataTable
的属性值)或重置它。
private async Task GetWorkingCalendarAsync()
{
...
bool hasChanges;
foreach (DataRow row in HariKerjaTable.Rows)
{
DateTime date = DateTime.Parse(row["date_calendar"].ToString());
Debug.WriteLine(date.ToString("ddd\ndd"));
if (!KalenderKerjaTable.Columns.Contains(date.ToString("ddd\ndd")))
{
hasChanges = true;
KalenderKerjaTable.Columns.Add(date.ToString("ddd\ndd"));
}
}
if (hasChanges)
{
// Option 1: replace
KalenderKerjaTable = KalenderKerjaTable.DefaultView.ToTable();
// Option 2: reset
var tableTemp = KalenderKerjaTable;
KalenderKerjaTable = null;
KalenderKerjaTable = tableTemp;
}
}