MVVM 从 ViewModel 刷新数据网格,即使集合没有改变
MVVM Refresh Datagrid from ViewModel even when collection doesn't change
我正在编写一个应用程序来读取和分析我公司软件使用的一些日志。有多种类型的日志,但为了描述我的问题,我们只取两种。即 TypeA
和 TypeB
的日志。我设计了一个 class 来保存一行日志数据,名为 LogLine
如下所示。
public class LogLine
{
public long LineNum { get; set; }
public string Msg { get; set; }
}
这是我的problem/requirement。
在我的主 ViewModel
中,我想在应用程序加载时只读取每种类型的日志一次。读取 TypeA
次日志,并存储在 ObservableCollection
个 LogLine
实例中,对 TypeB
执行相同的操作。然后根据我的选择 DataGrid
显示一种类型的日志,如果我在任何时候单击一个按钮,相同的 DataGrid
应该显示另一种类型的日志。请注意,我的日志数据没有改变,我只是想显示我选择的日志。
为此,我创建了三个 classes,即 ControllerMain
、ControllerA
和 ControllerB
。最后两个像这样从前者派生:
public class ControllerMain
{
public ControllerMain()
{
LogLineList = new ObservableCollection<LogLine>();
}
private ObservableCollection<LogLine> logLineList;
public ObservableCollection<LogLine> LogLineList
{
get { return logLineList; }
set { logLineList = value; }
}
}
public class ControllerA : ControllerMain
{
public ControllerA() { }
// More stuff here
}
public class ControllerB : ControllerMain
{
public ControllerB() { }
// More stuff here
}
正如您所猜测的那样,ControllerA
旨在保存 TypeA
的日志,以及这些日志独有的相关属性和方法。 TypeB
日志也是如此。
在我的 ViewModel
中,我有上面每个 classes 的实例,并且在应用程序加载时我读取日志数据并存储在适当的 class 对象中。
public ControllerMain COMMON_LOG { get; set; }
public ControllerA A_LOG { get; set; }
public ControllerB B_LOG { get; set; }
public ViewModelMain()
{
isAType = true;
ClickCommand = new CustomCommand(ClickCmd, CanClickCmd);
A_LOG = new ControllerA
{
// This simulates reading logs from files - done only once
LogLineList = DataService.GetAData()
};
B_LOG = new ControllerB
{
// This simulates reading logs from files - done only once
LogLineList = DataService.GetBData()
};
// This simulates switching to already loaded logs.
// When I do this the log lines don't change, but I want to refresh the datagrid and display correct info.
LoadAppropriateLog();
}
private void LoadAppropriateLog()
{
if (isAType)
{
COMMON_LOG = A_LOG;
isAType = false;
}
else
{
COMMON_LOG = B_LOG;
isAType = true;
}
}
我的 View
绑定到 COMMON_LOG
实例,如下所示:
<DataGrid Grid.Row="0" Margin="5"
Name="dgLogs"
AutoGenerateColumns="False" SelectionUnit="CellOrRowHeader"
ItemsSource="{Binding COMMON_LOG.LogLineList}">
然后点击一个按钮,我调用上面的 LoadAppropriateLog()
方法,所以它会简单地将适当类型的实例分配给 COMMON_LOG
这是我用来数据的实例绑定。
问题是,当我这样做时,由于每个实例 LogLineList
中的实际数据没有改变,DataGrid
不会自动更新以反映我选择的日志。
有没有办法在我每次切换日志类型后从我的 ViewModel
手动刷新 DataGrid
?
如果您想 运行 项目并查看,这里有一个下载 link:
如果您要绑定到 XAML 中 class 的 属性,或者
- 属性 在绑定第一次看到它后永远不应该改变它的值,并且通常应该是只读的,只是为了避免事故——或者
- class 应该实现
INotifyPropertyChanged
而 属性 应该在其 setter 中提出 PropertyChanged
。
在您的例子中,您正在更改 COMMON_LOG
的值,而您永远不会更改其 LogLineList
的值。
tl;dr:因此您的主视图模型需要实现 INotifyPropertyChanged
,并在 setter 中为 COMMON_LOG
提高 PropertyChanged
。 任何不做这些事情的都不是视图模型。
LogLineList
作为 ObservableCollection
不会完成任何事情:class 所做的是在添加、删除或替换项目时发出通知。在绑定看到它之后的任何时候都不会发生这种情况。 ObservableCollection
的那些实例甚至不知道主视图模型的存在,因此当其属性更改时,它们肯定不会引发通知事件。他们也不应该:每个人都对他自己的通知负责。
事实上,如果您做出了这些集合在初始化后永不更改的设计决定,请使用 ReadOnlyCollection
而不是 ObservableCollection
。创建一个很容易:调用 List<T>.AsReadOnly<T>()
。对于任何 IEnumerable<T>
,只需调用 e.ToList().AsReadOnly()
。 ObservableCollection
信号 "you can add stuff to this"。但没有人应该。所以不要给他们想法。
我正在编写一个应用程序来读取和分析我公司软件使用的一些日志。有多种类型的日志,但为了描述我的问题,我们只取两种。即 TypeA
和 TypeB
的日志。我设计了一个 class 来保存一行日志数据,名为 LogLine
如下所示。
public class LogLine
{
public long LineNum { get; set; }
public string Msg { get; set; }
}
这是我的problem/requirement。
在我的主 ViewModel
中,我想在应用程序加载时只读取每种类型的日志一次。读取 TypeA
次日志,并存储在 ObservableCollection
个 LogLine
实例中,对 TypeB
执行相同的操作。然后根据我的选择 DataGrid
显示一种类型的日志,如果我在任何时候单击一个按钮,相同的 DataGrid
应该显示另一种类型的日志。请注意,我的日志数据没有改变,我只是想显示我选择的日志。
为此,我创建了三个 classes,即 ControllerMain
、ControllerA
和 ControllerB
。最后两个像这样从前者派生:
public class ControllerMain
{
public ControllerMain()
{
LogLineList = new ObservableCollection<LogLine>();
}
private ObservableCollection<LogLine> logLineList;
public ObservableCollection<LogLine> LogLineList
{
get { return logLineList; }
set { logLineList = value; }
}
}
public class ControllerA : ControllerMain
{
public ControllerA() { }
// More stuff here
}
public class ControllerB : ControllerMain
{
public ControllerB() { }
// More stuff here
}
正如您所猜测的那样,ControllerA
旨在保存 TypeA
的日志,以及这些日志独有的相关属性和方法。 TypeB
日志也是如此。
在我的 ViewModel
中,我有上面每个 classes 的实例,并且在应用程序加载时我读取日志数据并存储在适当的 class 对象中。
public ControllerMain COMMON_LOG { get; set; }
public ControllerA A_LOG { get; set; }
public ControllerB B_LOG { get; set; }
public ViewModelMain()
{
isAType = true;
ClickCommand = new CustomCommand(ClickCmd, CanClickCmd);
A_LOG = new ControllerA
{
// This simulates reading logs from files - done only once
LogLineList = DataService.GetAData()
};
B_LOG = new ControllerB
{
// This simulates reading logs from files - done only once
LogLineList = DataService.GetBData()
};
// This simulates switching to already loaded logs.
// When I do this the log lines don't change, but I want to refresh the datagrid and display correct info.
LoadAppropriateLog();
}
private void LoadAppropriateLog()
{
if (isAType)
{
COMMON_LOG = A_LOG;
isAType = false;
}
else
{
COMMON_LOG = B_LOG;
isAType = true;
}
}
我的 View
绑定到 COMMON_LOG
实例,如下所示:
<DataGrid Grid.Row="0" Margin="5"
Name="dgLogs"
AutoGenerateColumns="False" SelectionUnit="CellOrRowHeader"
ItemsSource="{Binding COMMON_LOG.LogLineList}">
然后点击一个按钮,我调用上面的 LoadAppropriateLog()
方法,所以它会简单地将适当类型的实例分配给 COMMON_LOG
这是我用来数据的实例绑定。
问题是,当我这样做时,由于每个实例 LogLineList
中的实际数据没有改变,DataGrid
不会自动更新以反映我选择的日志。
有没有办法在我每次切换日志类型后从我的 ViewModel
手动刷新 DataGrid
?
如果您想 运行 项目并查看,这里有一个下载 link:
如果您要绑定到 XAML 中 class 的 属性,或者
- 属性 在绑定第一次看到它后永远不应该改变它的值,并且通常应该是只读的,只是为了避免事故——或者
- class 应该实现
INotifyPropertyChanged
而 属性 应该在其 setter 中提出PropertyChanged
。
在您的例子中,您正在更改 COMMON_LOG
的值,而您永远不会更改其 LogLineList
的值。
tl;dr:因此您的主视图模型需要实现 INotifyPropertyChanged
,并在 setter 中为 COMMON_LOG
提高 PropertyChanged
。 任何不做这些事情的都不是视图模型。
LogLineList
作为 ObservableCollection
不会完成任何事情:class 所做的是在添加、删除或替换项目时发出通知。在绑定看到它之后的任何时候都不会发生这种情况。 ObservableCollection
的那些实例甚至不知道主视图模型的存在,因此当其属性更改时,它们肯定不会引发通知事件。他们也不应该:每个人都对他自己的通知负责。
事实上,如果您做出了这些集合在初始化后永不更改的设计决定,请使用 ReadOnlyCollection
而不是 ObservableCollection
。创建一个很容易:调用 List<T>.AsReadOnly<T>()
。对于任何 IEnumerable<T>
,只需调用 e.ToList().AsReadOnly()
。 ObservableCollection
信号 "you can add stuff to this"。但没有人应该。所以不要给他们想法。