Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在虚拟机之间保存信息_C#_Wpf_Mvvm_Data Binding - Fatal编程技术网

C# 在虚拟机之间保存信息

C# 在虚拟机之间保存信息,c#,wpf,mvvm,data-binding,C#,Wpf,Mvvm,Data Binding,我正在尝试做的主要想法是拥有一个虚拟机,它拥有许多其他虚拟机。 问题是如何组织数据传输 主虚拟机与模板连接,其他虚拟机有自己的模板。 我使用导航器更改VM,使用模板选择器更改模板 导航器: public class NavigationController : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private List<ViewModelBa

我正在尝试做的主要想法是拥有一个虚拟机,它拥有许多其他虚拟机。 问题是如何组织数据传输

主虚拟机与模板连接,其他虚拟机有自己的模板。 我使用导航器更改VM,使用模板选择器更改模板

导航器:

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);
        }
    }
}