C# 在虚拟机之间保存信息
我正在尝试做的主要想法是拥有一个虚拟机,它拥有许多其他虚拟机。 问题是如何组织数据传输 主虚拟机与模板连接,其他虚拟机有自己的模板。 我使用导航器更改VM,使用模板选择器更改模板 导航器:C# 在虚拟机之间保存信息,c#,wpf,mvvm,data-binding,C#,Wpf,Mvvm,Data Binding,我正在尝试做的主要想法是拥有一个虚拟机,它拥有许多其他虚拟机。 问题是如何组织数据传输 主虚拟机与模板连接,其他虚拟机有自己的模板。 我使用导航器更改VM,使用模板选择器更改模板 导航器: public class NavigationController : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private List<ViewModelBa
public class NavigationController : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<ViewModelBase> _viewModels;
private ViewModelBase _currentViewModel;
public ViewModelBase CurrentViewModel {
get { return _currentViewModel; }
set { _currentViewModel = value; OnPropertyChanged(nameof(CurrentViewModel)); }
}
private List<ViewModelBase> _legViewModels;
private ViewModelBase _legViewModel;
public ViewModelBase LegViewModel
{
get { return _legViewModel; }
set { _legViewModel = value; OnPropertyChanged(nameof(LegViewModel)); }
}
public NavigationController()
{
_viewModels = new List<ViewModelBase>
{
new ViewModelLogin(this),
new ViewModelPhysicalOverview(this),
...list of VMs...
};
_currentViewModel = _viewModels.First();
_legViewModels = new List<ViewModelBase>
{
new SFSViewModel(this),
new BPVHipViewModel(this)
};
_legViewModel = _legViewModels.First();
}
public void NavigateTo<T>()
{
var target = _viewModels.FirstOrDefault(e => e.GetType() == typeof(T));
if (target != null)
CurrentViewModel = target;
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
//если PropertyChanged не нулевое - оно будет разбужено
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
在我返回到父屏幕之前触发的fn:
SaveCommand = new DelegateCommand(
() =>
{
IsEmpty = false;
Controller.NavigateTo<ViewModelAddPhysical>();
}
);
SaveCommand=newdelegateCommand(
() =>
{
IsEmpty=false;
Controller.NavigateTo();
}
);
所以,我想从主模板按钮,以显示我们是否已经访问了子屏幕,在这种情况下,我想“编辑”文本。但它总是返回“Fill”,因为对于他来说,IsEmpty不会从真变假,我不知道如何修复它。请帮忙。所以我似乎从来没有这样做过。你看过温莎吗。我相信依赖注入和控制反转可以提高这里的可伸缩性。就建议而言 这里的代码中有许多不同的地方正在进行实例化。也许创建一个工厂来处理所有的新问题。国际奥委会也将为此提供帮助。您可以在全球范围内放置模型列表<代码>App.Current.Properties[“someVm”]=vmInstance代码>如果要保存vm状态。 当然,另一种持久化vm状态的方法是将该vm设置为单例,确保在调用时,它只返回已经存在的实例,或者在不存在的情况下实例化该实例。
最后,我在卸载时保持vm状态,并在加载时从某处读取状态。这是常见的,许多默认控件都会这样做。对我来说,你正试图发明一个自己的轮子。已经做了很多次了。每个MVVM框架都有内置的导航 看看ReactiveUI(伟大的框架),它们正是您所需要的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;
using ReactiveUI.Samples.Routing.Views;
using Splat;
namespace ReactiveUI.Samples.Routing.ViewModels
{
/* COOLSTUFF: What is the AppBootstrapper?
*
* The AppBootstrapper is like a ViewModel for the WPF Application class.
* Since Application isn't very testable (just like Window / UserControl),
* we want to create a class we can test. Since our application only has
* one "screen" (i.e. a place we present Routed Views), we can also use
* this as our IScreen.
*
* An IScreen is a ViewModel that contains a Router - practically speaking,
* it usually represents a Window (or the RootFrame of a WinRT app). We
* should technically create a MainWindowViewModel to represent the IScreen,
* but there isn't much benefit to split those up unless you've got multiple
* windows.
*
* AppBootstrapper is a good place to implement a lot of the "global
* variable" type things in your application. It's also the place where
* you should configure your IoC container. And finally, it's the place
* which decides which View to Navigate to when the application starts.
*/
public class AppBootstrapper : ReactiveObject, IScreen
{
public RoutingState Router { get; private set; }
public AppBootstrapper(IMutableDependencyResolver dependencyResolver = null, RoutingState testRouter = null)
{
Router = testRouter ?? new RoutingState();
dependencyResolver = dependencyResolver ?? Locator.CurrentMutable;
// Bind
RegisterParts(dependencyResolver);
// TODO: This is a good place to set up any other app
// startup tasks, like setting the logging level
LogHost.Default.Level = LogLevel.Debug;
// Navigate to the opening page of the application
// you can set any property of this new VM to transport data
Router.Navigate.Execute(new WelcomeViewModel(this));
}
private void RegisterParts(IMutableDependencyResolver dependencyResolver)
{
dependencyResolver.RegisterConstant(this, typeof(IScreen));
dependencyResolver.Register(() => new WelcomeView(), typeof(IViewFor<WelcomeViewModel>));
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用Ninject;
使用ReactiveUI.Samples.Routing.Views;
使用Splat;
命名空间ReactiveUI.Samples.Routing.ViewModels
{
/*什么是AppBootstrapper?
*
*AppBootstrapper类似于WPF应用程序类的ViewModel。
*由于应用程序不是很容易测试(就像Window/UserControl一样),
*我们想创建一个可以测试的类。因为我们的应用程序只有
*一个“屏幕”(即我们呈现路线视图的位置),我们也可以使用
*这是我们的IScreen。
*
*IScreen是一个包含路由器的ViewModel——实际上,
*它通常表示一个窗口(或WinRT应用程序的根框架)
*技术上应该创建一个MainWindowViewModel来表示IScreen,
*但是,除非你有多个目标,否则分割这些目标没有多大好处
*窗户。
*
*AppBootstrapper是实现许多“全局应用程序”的好地方
*变量”类型的东西。它也是
*你应该配置你的IoC容器。最后,它就是这个地方
*它决定应用程序启动时导航到哪个视图。
*/
公共类AppBootstrapper:ReactiveObject,IScreen
{
公共路由状态路由器{get;private set;}
公用AppBootstrapper(IMutableDependencyResolver dependencyResolver=null,RoutingState testRouter=null)
{
路由器=测试路由器??新路由状态();
dependencyResolver=dependencyResolver??Locator.CurrentMutable;
//束缚
寄存器部件(从属解析程序);
//TODO:这是安装任何其他应用程序的好地方
//启动任务,如设置日志记录级别
LogHost.Default.Level=LogLevel.Debug;
//导航到应用程序的打开页面
//您可以将此新VM的任何属性设置为传输数据
Router.Navigate.Execute(新的WelcomeViewModel(this));
}
私有无效注册表部分(IMutableDependencyResolver dependencyResolver)
{
RegisterConstant(this,typeof(IScreen));
dependencyResolver.Register(()=>new WelcomeView(),typeof(IViewFor));
}
}
}
我使用了MessageBus模式,这对我来说是一个完美的解决方案
class Subscription
{
public object Instance { get; set; }
public Action<object, object> Handler;
}
public class MessageBus
{
#region Singleton
private static readonly MessageBus _instance = new MessageBus();
public static MessageBus Default => _instance;
private MessageBus()
{
}
#endregion
private readonly Dictionary<string, List<Action<object, object>>> _hadlersMap
= new Dictionary<string, List<Action<object, object>>>();
public void Call(string name, object sender, object data)
{
List<Action<object, object>> handlers;
if(!_hadlersMap.TryGetValue(name.ToUpper(), out handlers))
return;
foreach (var handler in handlers)
{
handler?.Invoke(sender,data);
}
}
public void Subscribe(string name, Action<object, object> handler)
{
name = name.ToUpper();
List<Action<object, object>> handlers;
if (!_hadlersMap.TryGetValue(name, out handlers))
{
handlers = new List<Action<object, object>>{ handler };
_hadlersMap.Add(name, handlers);
}
else
{
handlers.Add(handler);
}
}
}
类订阅
{
公共对象实例{get;set;}
公共行动处理人;
}
公共类消息总线
{
#区域单态
私有静态只读MessageBus_实例=新MessageBus();
公共静态MessageBus默认值=>\u实例;
私有消息总线()
{
}
#端区
专用只读词典
=新字典();
公共void调用(字符串名称、对象发送方、对象数据)
{
列表处理程序;
if(!\u hadlersMap.TryGetValue(name.ToUpper(),out handlers))
回来
foreach(处理程序中的变量处理程序)
{
处理程序?.Invoke(发送方、数据);
}
}
public void Subscribe(字符串名称、操作处理程序)
{
name=name.ToUpper();
列表处理程序;
if(!\u hadlersMap.TryGetValue(名称,输出处理程序))
{
handlers=新列表{handler};
_Add(名称、处理程序);
}
其他的
{
添加(handler);
}
}
}
对不起,信息太多了。也许你可以用例子展示一些链接?标题说你想在虚拟机之间保存数据。Singleton将在应用程序生命周期内完成这项工作,并在视图卸载事件时序列化数据,在视图加载事件时读取或反序列化也是保存vm状态的常用方法。坚持应用程序属性也是如此。查看MVVMLight。我在大多数WPF项目中都使用它,它提供了视图模型定位器和导航方案。链接[]-[]-[]Oh和MvvmLight提供一个DelegateCommand im
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;
using ReactiveUI.Samples.Routing.Views;
using Splat;
namespace ReactiveUI.Samples.Routing.ViewModels
{
/* COOLSTUFF: What is the AppBootstrapper?
*
* The AppBootstrapper is like a ViewModel for the WPF Application class.
* Since Application isn't very testable (just like Window / UserControl),
* we want to create a class we can test. Since our application only has
* one "screen" (i.e. a place we present Routed Views), we can also use
* this as our IScreen.
*
* An IScreen is a ViewModel that contains a Router - practically speaking,
* it usually represents a Window (or the RootFrame of a WinRT app). We
* should technically create a MainWindowViewModel to represent the IScreen,
* but there isn't much benefit to split those up unless you've got multiple
* windows.
*
* AppBootstrapper is a good place to implement a lot of the "global
* variable" type things in your application. It's also the place where
* you should configure your IoC container. And finally, it's the place
* which decides which View to Navigate to when the application starts.
*/
public class AppBootstrapper : ReactiveObject, IScreen
{
public RoutingState Router { get; private set; }
public AppBootstrapper(IMutableDependencyResolver dependencyResolver = null, RoutingState testRouter = null)
{
Router = testRouter ?? new RoutingState();
dependencyResolver = dependencyResolver ?? Locator.CurrentMutable;
// Bind
RegisterParts(dependencyResolver);
// TODO: This is a good place to set up any other app
// startup tasks, like setting the logging level
LogHost.Default.Level = LogLevel.Debug;
// Navigate to the opening page of the application
// you can set any property of this new VM to transport data
Router.Navigate.Execute(new WelcomeViewModel(this));
}
private void RegisterParts(IMutableDependencyResolver dependencyResolver)
{
dependencyResolver.RegisterConstant(this, typeof(IScreen));
dependencyResolver.Register(() => new WelcomeView(), typeof(IViewFor<WelcomeViewModel>));
}
}
}
class Subscription
{
public object Instance { get; set; }
public Action<object, object> Handler;
}
public class MessageBus
{
#region Singleton
private static readonly MessageBus _instance = new MessageBus();
public static MessageBus Default => _instance;
private MessageBus()
{
}
#endregion
private readonly Dictionary<string, List<Action<object, object>>> _hadlersMap
= new Dictionary<string, List<Action<object, object>>>();
public void Call(string name, object sender, object data)
{
List<Action<object, object>> handlers;
if(!_hadlersMap.TryGetValue(name.ToUpper(), out handlers))
return;
foreach (var handler in handlers)
{
handler?.Invoke(sender,data);
}
}
public void Subscribe(string name, Action<object, object> handler)
{
name = name.ToUpper();
List<Action<object, object>> handlers;
if (!_hadlersMap.TryGetValue(name, out handlers))
{
handlers = new List<Action<object, object>>{ handler };
_hadlersMap.Add(name, handlers);
}
else
{
handlers.Add(handler);
}
}
}