Prism多视图绑定同一ViewModel构造函数触发两次及ListBox编辑问题咨询
问题1 构造函数触发两次的原因
Prism的RegisterForNavigation默认会将关联的ViewModel注册为瞬态服务,每次首次解析对应视图时都会创建新的ViewModel实例:
- 应用初始化时导航到
GCodeEditorView,首次解析创建第一个GCodeEditorViewModel实例 - 第一次切换到
GCodeProductionView时,因为该视图也绑定了GCodeEditorViewModel,首次解析时又创建了第二个实例 - 后续切换不会触发构造是因为Prism区域默认开启了视图缓存(
KeepAlive默认值为true),已经加载过的视图和关联的ViewModel会被直接复用,不会重新创建。
如果要实现两个视图共用同一个ViewModel实例,只需要在注册类型时手动将GCodeEditorViewModel注册为单例即可,修改RegisterTypes方法:
public void RegisterTypes(IContainerRegistry containerRegistry) { // 手动把ViewModel注册为单例 containerRegistry.RegisterSingleton<GCodeEditorViewModel>(); containerRegistry.RegisterForNavigation<MenuView, MenuViewModel>(); containerRegistry.RegisterForNavigation<GCodeEditorView, GCodeEditorViewModel>(); containerRegistry.RegisterForNavigation<GCodeProductionView, GCodeEditorViewModel>(); }
问题2 ListBox编辑项按回车新增行实现
你需要将GCode行数据绑定到ObservableCollection<T>类型的集合,同时绑定ListBox的选中项到ViewModel属性,通过监听编辑框的回车键事件触发新增逻辑即可,符合MVVM规范的实现方式如下:
- XAML部分配置ItemTemplate,用交互触发器将编辑框的键盘事件绑定到ViewModel命令:
<ListBox ItemsSource="{Binding GCodeLines}" SelectedItem="{Binding SelectedGCodeLine}"> <ListBox.ItemTemplate> <DataTemplate> <!-- 这里假设你用自定义GCode行实体类,Text绑定行内容属性 --> <TextBox Text="{Binding Content, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <i:Interaction.Triggers> <i:EventTrigger EventName="KeyDown"> <prism:InvokeCommandAction Command="{Binding DataContext.AddNewLineCommand, RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding}" PassEventArgsToCommand="True"/> </i:EventTrigger> </i:Interaction.Triggers> </TextBox> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
- ViewModel新增命令逻辑:
// GCode行集合 public ObservableCollection<GCodeLineModel> GCodeLines { get; set; } // 当前选中行 public GCodeLineModel SelectedGCodeLine { get; set; } private void ExecuteAddNewLineCommand(object parameter) { var args = (KeyEventArgs)parameter; // 只响应回车键 if (args.Key != Key.Enter) return; var currentLine = (GCodeLineModel)((InvokeCommandAction)args.Source).CommandParameter; int currentIndex = GCodeLines.IndexOf(currentLine); // 在当前行下方插入空行 GCodeLines.Insert(currentIndex + 1, new GCodeLineModel() { Content = string.Empty }); // 自动选中新行直接进入编辑状态 SelectedGCodeLine = GCodeLines[currentIndex + 1]; RaisePropertyChanged(nameof(SelectedGCodeLine)); }
内容的提问来源于stack exchange,提问作者Buruhazard
相关产品推荐
相关产品推荐

