Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何在Catel中实现具有撤销/重做支持的更改状态对话框?

如何在Catel中实现具有撤销/重做支持的更改状态对话框?
EN

Stack Overflow用户
提问于 2014-09-08 06:56:34
回答 1查看 182关注 0票数 0

在使用对话框时,我无法恢复和重做以正确行为。

我有一个简单的模型,它的属性指示对象(runningpausedstopped)的状态,可以通过对话框来修改。所发生的情况是,我得到的操作似乎在撤消队列中什么都不做,或者撤销将对象还原到中间状态。

模型对象在构造函数中用memento注册。对话框有三个单选按钮,每个按钮代表三种不同状态中的一种。每个单选按钮都绑定到每个命令。每个命令都执行属性的更改。我尝试了两种不同的方法,要么每个命令直接在对象中设置属性,要么每个命令在调用时为视图模型设置一个实例变量,然后使用Saving修改对象。

如果使用第一种方法,则在对话框中单击Ok之前,如果用户单击多个无线电按钮,则将每个属性更改放到撤消队列中。试图通过将整个对话框包装成一个批处理来解决这个问题,但结果是取消状态更改,对象将恢复到它在最后一个状态之前的状态,也就是说,如果该属性在对话框打开之前设置为stopped,并且用户按下暂停无线电按钮,然后启动一个,最后确定,撤销将将该属性设置为paused而不是预期的stopped

如果使用第二种方法,用户打开对话框,将状态更改为paused,在对话框中单击Ok,撤销/重做将按预期的方式进行,但如果再次打开对话框并选择取消,则会向撤消队列添加另一个操作,即用户必须单击“撤消”两次才能返回到初始的stopped-state。

因此,我的问题是,应该如何正确地实现这一点以获得预期的行为:每个对话框的交互都可以取消,而不是对话中的每一个交互?

下面是ViewModel的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
namespace UndoRedoTest.ViewModels
{
    using Catel.Data;
    using Catel.MVVM;
    public class StartStopViewModel : ViewModelBase
    {
        Machine.MachineState _state;
        public StartStopViewModel(Machine controlledMachine) 
        {
            ControlledMachine = controlledMachine;
            _state = controlledMachine.State;
            StartMachine = new Command(OnStartMachineExecute);
            PauseMachine = new Command(OnPauseMachineExecute);
            StopMachine = new Command(OnStopMachineExecute);
            Saving += StartStopViewModel_Saving;
        }

        void StartStopViewModel_Saving(object sender, SavingEventArgs e)
        {
            ControlledMachine.State = _state;
        }

        [Model]
        public Machine ControlledMachine
        {
            get { return GetValue<Machine>(ControlledMachineProperty); }
            private set { SetValue(ControlledMachineProperty, value); }
        }

        public static readonly PropertyData ControlledMachineProperty = RegisterProperty("ControlledMachine", typeof(Machine));

        public override string Title { get { return "Set Machine state"; } }

        public Command StartMachine { get; private set; }
        public Command PauseMachine { get; private set; }
        public Command StopMachine { get; private set; }

        private void OnStartMachineExecute()
        {
            _state = Machine.MachineState.RUNNING;
            //ControlledMachine.SecondState = Machine.MachineState.RUNNING;
        }

        private void OnPauseMachineExecute()
        {
            _state = Machine.MachineState.PAUSED;
            //ControlledMachine.SecondState = Machine.MachineState.PAUSED;
        }

        private void OnStopMachineExecute()
        {
            _state = Machine.MachineState.STOPPED;
            //ControlledMachine.SecondState = Machine.MachineState.STOPPED;
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-09 03:32:24

首先,不要订阅Saving,而只是重写Save()方法。注意,Catel在用ModelAttribute装饰模型时为您处理模型状态。因此,您需要获得对话框的预状态和后置状态,然后将结果集推到批处理中。

例如,我将为对象类(或模型类)创建如下扩展方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static Dictionary<string, object> GetProperties(this IModel model)
{
    // todo: return properties
}

然后在Initialize和Save方法中这样做,您将拥有2组属性(预状态和post状态)。现在,我们可以很容易地计算出这些差异:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static Dictionary<string, object> GetChangedProperties(Dictionary<string, object> preState, Dictionary<string, object> postState)
{
    // todo: calculate difference
}

现在您有了区别,您可以创建一个备忘录批处理,它将恢复您预期的确切状态。

ps。如果你能把它写进一篇博客文章,或者用这个功能创建一个公关,那就太好了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25727174

复制
相关文章
C++11异步编程(std::async, std::future, std::packaged_task, std::promise)
       std::async是一个函数模板,会启动一个异步任务,最终返回一个std::future对象。在之前我们都是通过thread去创建一个子线程,但是如果我们要得到这个子线程所返回的结果,那么可能就需要用全局变量或者引用的方法来得到结果,这样或多或少都会不太方便,那么async这个函数就可以将得到的结果保存在future中,然后通过future来获取想要得到的结果。async比起thread来说可以对线程的创建又有了更好的控制,比如可以延迟创建。下面先介绍一下std::future, std::packaged_task, std::promise。
Ch_Zaqdt
2020/02/15
16.1K0
C++11 std::async
//g++ -std=c++11 -pthread -g std_future.cpp -o main // async example #include <iostream> // std::cout #include <future> // std::async, std::future // a non-optimized way of checking for prime numbers: bool is_prime (long int x) { std::co
awk
2018/08/23
4680
C++11 std::bind std::function 高级使用方法[通俗易懂]
Hello world ! sumFunc.Call<int>(1, 2, 3) : 6
全栈程序员站长
2022/02/04
9970
c++11:std::copy示例
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/84709909
10km
2019/05/25
1.7K0
std::function与std::bind
一、背景介绍: 函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器,他们配合起来能够很好的替代函数指针。
灰子学技术
2022/01/18
9360
C++11:基于std::queue和std::mutex构建一个线程安全的队列
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/52067929
10km
2019/05/25
10.7K0
cmake+gcc解决extended initializer lists only available with -std=c++11 or -std=gnu++11
有时,我们需要一个结构体变量做为参数传递给函数,后面又不需要再用到这个结构体变量,所以如果专门定义一个变量,再将这个变量传递给函数就显得挺罗嗦。 就像下面这段代码,tmpStruct只是起到一个数据包装的作用,调用test()之后并不再用到,所以这个变量就显示有些多余 。
10km
2022/05/07
6350
理解std::move和std::forward
std::move和std::forward只是执行转换的函数(确切的说应该是函数模板)。std::move无条件的将它的参数转换成一个右值,而std::forward当特定的条件满足时,才会执行它的转换。这就是它们本来的样子.这样的解释产生了一些新问题,但是,基本上就是这么一回事。
杨永贞
2022/06/08
1.8K0
理解std::move和std::forward
std::jthread与std::thread区别
​std::jthread是C++20新引入的线程类,与 std::thread 类似,或者说,jthread是对thread进一步的封装,功能更强大​。
音视频牛哥
2022/04/03
1.3K0
std::atomic和std::mutex区别
​模板类std::atomic是C++11提供的原子操作类型,头文件 #include<atomic>。​在多线程调用下,利用std::atomic可实现数据结构的无锁设计。​​
音视频牛哥
2022/03/12
2.9K0
std::atomic和std::mutex区别
C++11 std::lock_guard 互斥锁
C++11中加入了线程,引入了多线程,也就伴随着一个多线程资源互斥的操作。对于锁的使用,有一个比较头疼的问题,就是在加锁后,容易忘记解锁,这样程序中可能会造成死锁。C++11中加入了lock_guard,这个的使用,可以让你不用关注解锁!
fensnote
2021/05/31
1.7K0
c++11:如何判断std::function对象相同?
我们知道std::function的实质就是个函数指针,但在c++11中std::function并没有实现操作符==(要到C++20才实现),所以我们无法使用==操作符来判断两个std::function对象是否相等,虽然我们明明知道它就是个指针。
10km
2020/04/08
1.8K0
<c++ 常用代码块> | std::string 与 std::wstring转化
#include <string>#include <locale>#include <codecvt>// convert string to wstringinline std::wstring to_wide_string(const std::string& input){std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;return converter.from_bytes(input);}// convert wstring t
IsEva
2022/12/05
9890
c++中的std::stod, stCPP程序说明std::stod():stof, std::stold
如果未执行转换,则会引发invalid_argument异常。如果读取的值超出双精度的可表示值范围,则会引发out_of_range异常。无效的 idx 会导致未定义的行为。
鲸落c
2022/12/14
3K0
想看懂WebRtc,你须知道的C++11新特性「lambda,std::function以及std:bind」
在本文中,我们来聊一下lambda表达式,闭包,std::function以及std::bind。
音视频_李超
2020/04/02
8430
std::function与std::bind使用总结
C++中函数指针的用途非常广泛,例如回调函数,接口类的设计等,但函数指针始终不太灵活,它只能指向全局或静态函数,对于类成员函数、lambda表达式或其他可调用对象就无能为力了,因此,C++11推出了std::function与std::bind这两件大杀器。
forrestlin
2019/07/29
11.4K0
诡异!std::bind in std::bind 编译失败
当时看了报错,简单的以为跟之前遇到的原因一样,随即提出了解决方案,怎奈,短短几分钟,就被无情打脸,啪啪啪😭。为了我那仅存的一点点自尊,赶紧看下原因,顺便把之前的问题也回顾下。
高性能架构探索
2023/06/13
7880
诡异!std::bind in std::bind 编译失败
C++11特性之std:call_once介绍
std:call_once是C++11引入的新特性,如需使用,只需要#include <mutex>即可,简单来说std:call_once的作用,确保函数或代码片段在多线程环境下,只需要执行一次,常用的场景如Init()操作或一些系统参数的获取等。
音视频牛哥
2022/05/12
2.3K0
C++11特性之std:call_once介绍
[C++11札记]: std::function
在C/C++中函数指针作为一种回调机制被广泛使用,但是函数指针在C++面向对象编程中有些不足,比如无法捕捉上下文。举个例子,使用对象的非静态成员函数作为函数指针就无法做到。
acoolgiser
2019/06/14
2.2K0
[C++11札记]: std::bind
在上一篇文章中,我们提到可调用对象(callable object),其中一种就是std::bind表达式。在这篇文章中,我们来谈谈std::bind表达式。
云水木石
2019/07/02
1.5K0

相似问题

带有std::weak_ptr的std::make_shared分配

28

std::make_shared()、std::weak_ptr和循环引用

37

std::std::weak_ptr向量和std::查找

11

std:bind和std::weak_ptr

13

成员函数中与本地静态std::map<std::string、std::weak_ptr>的访问冲突(C++11/STL)

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文