一、MVVM的Model、View、ViewModel分工
1.View
- 负责界面和显示,界面构成元素有window, controls, page, dataTemplete, custom
controls…. - 代码通常有XAML和XAML.CS组成,但后台代码应该很少
- 通过DataContext和ViewModel绑定不直接和Model交互!
- 控件可以和ViewModel的公共属性绑定,update需要双向绑定
- 控件可以触发Behavior/Command调用ViewModel的方法,Command是View到ViewModel的单向通讯 (View中触发事件,ViewModel中处理事件)
2.ViewModel
- 主要包括界面逻辑和模型数据封装,Behavior/Command事件响应,绑定的属性定义等
- ViewModel继承Model类,或者是Model的继承类
是view和model的桥梁,是对Model的抽象,例如,model中数据格式是“年月日”,可以在viewModel中转换model中的数据为“日月年”以供视图(view)显示。 - 维护视图状态
- 实现属性或集合的change notification
-
3. Model
- 数据和业务逻辑
- 客户端领域模型
- 由data entities, business objects, repositories and services构成
- 可以实现属性或集合的change notification
- 可以实现validation 接口例如 IDataErrorInfo
二、 MVVM
View和ViewModel数据绑定和交互
View和ViewModel主要通过数据绑定和Command/Behavior进行交互,如下图所示:
private void InitializeCommandHandlers()
{
//突发事件
AccidentsWindowHelper.InitializeParentCommandHandlers(this);
//事件线索
this.AccidentCluesCommandHandler();
//预案管理
this.PlansCommandHandler();
//复制Plot到当前打开的文档
this.CommandBindings.Add(new CommandBinding(Commands.HomeCopyPlotToCurrentWord, CopyPlotToWordHandler, (sender, e) => {
e.CanExecute = e.Parameter is MapPlot &&
LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;// MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED;
}));
//态势标绘
MapPlotHelper.InitializeParentCommandHandlers(this);
//综合态势
MapPlotStateHelper.InitializeParentCommandHandlers(this);
//大数据资源池
this.BigDataResPoolCommandHandler();
//显示首页列表
this.CommandBindings.Add(new CommandBinding(Commands.HomePage, HomePageCommandHandler, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;// MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED;
}));
//创建WORD文档
this.CommandBindings.Add(new CommandBinding(Commands.CreateWord, CreateWordCommandHandler, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ && MainWindowViewModel.Current.IsWordAvailable;
#else
e.CanExecute = false;
#endif
}));
//选择已经显示的文档
this.CommandBindings.Add(new CommandBinding(Commands.SelectOpeningIntel, (sender, arg) => {
IntelBase intel = arg.Parameter as IntelBase;
try {
this.WordContainer.WordControl.ShowDocument(intel.ID);
OpeningIntelsViewModel.Current.ShowIntel(intel.ID);
} catch (Exception ex) {
LogHelper.e("MainWindow.WordNavigator.OnItemSelectedEvent -> ", ex);
}
}, (sender, e) => {
e.CanExecute = e.Parameter != null;
}));
//关闭显示的文档
this.CommandBindings.Add(new CommandBinding(Commands.CloseOpeningIntel, CloseOpeningIntelCommandHandler));
//修改产品标题
this.CommandBindings.Add(new CommandBinding(Commands.EditProductTitle, EditProductTitleCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
// && (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& product.IsDraft;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//上报产品
this.CommandBindings.Add(new CommandBinding(Commands.ReportProduct, ReportProductCommandHandler, (sender, e) => {
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else if (e.Parameter is Information information)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else if (e.Parameter is PaperWork paperwork)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& paperwork.File != null && (paperwork.File.FileType == IntelFileType.XMLDOC ||
paperwork.File.FileType == IntelFileType.WORD) && !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else
{
e.CanExecute = false;
}
}));
//上报突发事件
this.CommandBindings.Add(new CommandBinding(Commands.ReportAccident, ReportAccidentCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else if (e.Parameter is Information information)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else if (e.Parameter is PaperWork paperwork)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& paperwork.File != null && (paperwork.File.FileType == IntelFileType.XMLDOC ||
paperwork.File.FileType == IntelFileType.WORD) && !UnitHelper.IsTopUnit(UnitHelper.MyUnit);
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//查看推送信息
this.CommandBindings.Add(new CommandBinding(Commands.ViewPushInfo, ViewPushInfoCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = product.IsPushed && LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//另存为新产品
this.CommandBindings.Add(new CommandBinding(Commands.SaveAsNewProduct, SaveAsNewProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else e.CanExecute = false;
#else
e.CanExecute = false;
#endif
}));
//发送产品到其他单位
this.CommandBindings.Add(new CommandBinding(Commands.SendProduct, SendProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else if (e.Parameter is Information information)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else if (e.Parameter is PaperWork paperwork)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//产品推送
this.CommandBindings.Add(new CommandBinding(Commands.PushProduct, PushProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = (!product.IsPushed) && LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//取消产品推送
this.CommandBindings.Add(new CommandBinding(Commands.CancelPushProduct, CancelPushProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = product.IsPushed && LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//归档
this.CommandBindings.Add(new CommandBinding(Commands.ArchiveProduct, ArchiveProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& product.IsDraft;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//重新编辑
this.CommandBindings.Add(new CommandBinding(Commands.ReeditProduct, ReeditProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& !product.IsDraft;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//添加本地文件为产品
this.CommandBindings.Add(new CommandBinding(Commands.ImportLocalWordAsProduct,
ImportLocalWordAsProductCommandHandler, (sender, e) => {
#if !READER
e.CanExecute = true;
#else
e.CanExecute = false;
#endif
}));
//评价接收到的素材
this.CommandBindings.Add(new CommandBinding(Commands.CommentInformation, CommentInformationCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Information i)
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ && i.Receiver != null && UnitHelper.IsMyUnit(i.Receiver.ReceiveUnit));
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//查看上报素材的评价结果
this.CommandBindings.Add(new CommandBinding(Commands.ViewCommentInformation, ViewCommentInformationCommandHandler, (sender, e) => {
if (e.Parameter is Information i)
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ &&
UnitHelper.IsMyUnit(i.SendUnit) && i.HasEvaluated);
}
else
{
e.CanExecute = false;
}
}));
//标记优秀成果
this.CommandBindings.Add(new CommandBinding(Commands.MarkFavorite, MarkFavoriteCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Information i)
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ &&
i.Receiver != null && UnitHelper.IsMyUnit(i.Receiver.ReceiveUnit) && !i.IsExcellent);//是本单位接收的素材且未标注
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//标记优秀成果
this.CommandBindings.Add(new CommandBinding(Commands.MarkOrCancelFavorite, MarkOrCancelFavoriteCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Information i)
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ &&
i.Receiver != null && UnitHelper.IsMyUnit(i.Receiver.ReceiveUnit));//是本单位接收的素材
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//取消标记优秀成果
this.CommandBindings.Add(new CommandBinding(Commands.CancelFavorite, CancelFavoriteCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Information i)
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ &&
i.Receiver != null && UnitHelper.IsMyUnit(i.Receiver.ReceiveUnit) && i.IsExcellent);//是本单位接收的素材且已标注
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//为产品添加密码,将产品转换为带密码产品
this.CommandBindings.Add(new CommandBinding(Commands.ProductCreatePassword, (sender, arg) => {
Product p = arg.Parameter as Product;
if (p == null || p.Type != IntelType.PRODUCT)
return;
tryCloseOpenIntel(p);
ProductSecretCreateWindow win = new ProductSecretCreateWindow();
win.Product = p;
win.ShowDialog();
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//修改带密码产品的密码
this.CommandBindings.Add(new CommandBinding(Commands.ProductUpdatePassword, (sender, arg) => {
Product p = arg.Parameter as Product;
if (p == null || !p.IsSecret)
return;
ProductSecretUpdateWindow win = new ProductSecretUpdateWindow();
win.Product = p;
win.ShowDialog();
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//删除带密码产品的密码
this.CommandBindings.Add(new CommandBinding(Commands.ProductDeletePassword, (sender, arg) => {
Product p = arg.Parameter as Product;
if (p == null || !p.IsSecret)
return;
tryCloseOpenIntel(p);
ProductSecretDeleteWindow win = new ProductSecretDeleteWindow();
win.Product = p;
win.ShowDialog();
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//带密码产品验证授权
this.CommandBindings.Add(new CommandBinding(Commands.ProductVerifyPassword, (sender, arg) => {
Product p = arg.Parameter as Product;
if (p == null || !p.IsSecret)
return;
ProductSecretVerifyWindow win = new ProductSecretVerifyWindow();
win.Product = p;
win.ShowDialog();
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//打开一个产品
this.CommandBindings.Add(new CommandBinding(Commands.OpenProduct, OpenProductCommandHandler, (sender, e) => {
e.CanExecute = e.Parameter is Product
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//打开一个素材
this.CommandBindings.Add(new CommandBinding(Commands.OpenInformation, OpenInformationCommandHandler, (sender, e) => {
e.CanExecute = e.Parameter is Information
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//打印WORD文档
this.CommandBindings.Add(new CommandBinding(Commands.PrintWord, (sender, args) => {
PrintSettingWindow dialog = new PrintSettingWindow();
dialog.Control = this.WordContainer.WordControl;
//dialog.ShowDialog();
dialog.Owner = this;
dialog.Closed += Dialog_Closed;
ShowWindow(dialog);
//this.WordContainer.WordControl.Print();
}, (sender, e) => {
e.CanExecute = e.Parameter != null;
}));
//保存产品
this.CommandBindings.Add(new CommandBinding(Commands.SaveProduct, (sender, arg) => {
IntelBase p = null;
if (arg.Parameter is Product product)
{
p = product;
}
else if (arg.Parameter is ReportIntelProduct reportIntelProdu)
{
p = reportIntelProdu;
}
if (p == null)
return;
if (IsTrue(ConfigViewModel.Current.IsRecomEnable))
{
ServiceHelper.RecomLevel(p.ID, (errno1, message1, level) => {
if (errno1 == ErrorNo.SUCCESS)
{
ServiceHelper.RecomSecurity(p.ID, (errno2, message2, security) => {
if (errno2 == ErrorNo.SUCCESS)
{
Dispatcher.BeginInvoke((Action)(() => {
WordContainer.InnerWindow.Reload(p, level, security);
WordContainer.InnerWindow.Show();
}));
}
});
}
});
}
if (IsTrue(ConfigViewModel.Current.IsAreaCorrectEnable))
{
string content = this.WordContainer.WordControl.GetText();
if (content != null && content.Length > 0)
{
ServiceHelper.DistrictCheck(content, (errno, message, error_districts) => {
if (errno == ErrorNo.SUCCESS &&
error_districts != null && error_districts.Length > 0)
{
string[] tokens = error_districts.Split(
new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
if (tokens != null && tokens.Length > 0)
{
List<string> tokenList = new List<string>();
foreach (var token in tokens)
if (!tokenList.Contains(token))
tokenList.Add(token);
Dispatcher.BeginInvoke((Action)(() => {
this.WordContainer.WordControl.HitHighlight(tokenList.ToArray());
}));
}
}
});
}
}
if (IsTrue(ConfigViewModel.Current.IsRecomEnable))
TryRecomDoc(p);
this.Waiting("正在保存产品...", true, true);
try
{
if (!this.WordContainer.WordControl.Save(p.ID, true))
{
//this.CancelWaiting("保存失败!", true);
this.CancelWaiting();
this.ForceCancelWaiting();
ShowWarning("保存失败!");
}
}
catch (Exception ex)
{
//this.CancelWaiting("保存失败:" + ex.Message, true);
this.CancelWaiting();
this.ForceCancelWaiting();
ShowWarning("保存失败:" + ex.Message);
Log.LogHelper.e(ex.StackTrace);
Exception inner = ex.InnerException;
while (inner != null)
{
Log.LogHelper.e(inner.StackTrace);
inner = inner.InnerException;
}
}
}, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& product.IsDraft;
}
else if (e.Parameter is ReportIntelProduct reportIntelProduct)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& reportIntelProduct.IsDraft;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//将本地文件作为素材报告给上级
this.CommandBindings.Add(new CommandBinding(Commands.SendLocalFilesAsInformation, (sender, arg) => {
SendFileViewModel.Current.IsInformation = true;
this.ShowDialog(new SendFilesWindow());
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//将本地文件作为公文发送给其他单位
this.CommandBindings.Add(new CommandBinding(Commands.SendLocalFilesAsPaperWork, (sender, arg) => {
SendFileViewModel.Current.IsInformation = false;
this.ShowDialog(new SendFilesWindow());
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//删除产品
this.CommandBindings.Add(new CommandBinding(Commands.DeleteProduct, DeleteProductCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& product.IsDraft;
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//解除锁定产品
this.CommandBindings.Add(new CommandBinding(Commands.UnlockProduct, (sender, arg) => {
Product p = arg.Parameter as Product;
if (p == null || !p.IsLocked || !p.IsDraft)
return;
//尝试结束自己和别人的锁定
ProductIds.RemoveLockedProductId(p.ID);
this.Waiting("解除锁定...", true, true);
try
{
CommuService.Instance.UnlockProduct(p.ID, (status, msg, msgBean) => {
if (status != LongLink.Bean.EnumStatus.Success)
{
//this.CancelWaiting("解除锁定失败:" + result1, true);
this.CancelWaiting();
this.ForceCancelWaiting();
ShowWarning("解除锁定失败:" + msg);
}
else
{
p.IsLocked = false;
p.LockerId = "";
p.Save();
this.WordContainer.WordControl.UnlockDocument(p.ID);
//this.ShowMessage(ErrorNo.SUCCESS, "解除锁定成功!");
this.CancelWaiting("解除锁定成功。", true);
this.ForceCancelWaiting();
}
});
}
catch (Exception ex)
{
Log.LogHelper.w(ex.StackTrace);
//this.CancelWaiting("解除锁定失败:" + result1, true);
this.CancelWaiting();
this.ForceCancelWaiting();
ShowWarning("解除锁定失败:" + ex.Message);
}
}, (sender, e) => {
#if !READER
if (e.Parameter is Product product)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& (product.IsLocked /*&& product.LockerId == MainWindowViewModel.Current.Me.SN*/)
&& product.IsDraft;
}
else
e.CanExecute = false;
#else
e.CanExecute = false;
#endif
}));
//修改分类
this.CommandBindings.Add(new CommandBinding(Commands.ChangeClass, (sender, arg) => {
this.ShowDialog(new ChangeClassWindow(arg.Parameter as Product));
}, (sender, e) => {
#if !READER
e.CanExecute = e.Parameter is Product
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//修改密级
this.CommandBindings.Add(new CommandBinding(Commands.ChangeSecurity, (sender, arg) => {
this.ShowDialog(new ChangeSecurityWindow(arg.Parameter as IntelBase));
}, (sender, e) => {
#if !READER
e.CanExecute = e.Parameter is IntelBase
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//修改优先级
this.CommandBindings.Add(new CommandBinding(Commands.ChangeLevel, (sender, arg) => {
this.ShowDialog(new ChangeLevelWindow(arg.Parameter as IntelBase));
}, (sender, e) => {
#if !READER
e.CanExecute = e.Parameter is IntelBase
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//下载到本地并打开
this.CommandBindings.Add(new CommandBinding(Commands.GetIntelAndOpen, GetIntelAndOpenCommandHandler, (sender, e) => {
e.CanExecute = e.Parameter is IntelBase
&& LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示弹出消息
this.CommandBindings.Add(new CommandBinding(Commands.ShowPopupMessage, (sender, args) => {
if (args.Parameter is StatusBarViewModel.PopupMessageArgument arg) {
this.StatusBar.ShowPopMessage(arg.Content, arg.ActionContent, arg.ActionHandler, arg.ActionParam);
}
}));
//新建通知
this.CommandBindings.Add(new CommandBinding(Commands.NewNotice, (sender, args) => {
#if !READER
NoticesViewModel.Current.ReplyingIntel = null;
this.ShowDialog(new PostQuickWindow()
{
OnManageReplyOptions = OnManageReplyOptions,
});
#else
#endif
}));
//回复通知
this.CommandBindings.Add(new CommandBinding(Commands.ReplyNotice, (sender, args) => {
#if !READER
NoticesViewModel.Current.PostingNotice.Content = args.Parameter as string;
this.ShowDialog(new PostQuickWindow()
{
OnManageReplyOptions = OnManageReplyOptions,
});
#else
#endif
}));
//管理回复选项
this.CommandBindings.Add(new CommandBinding(Commands.ManageReplyOptions, (sender, arg) => {
#if !READER
this.OnManageReplyOptions();
#else
#endif
}));
#if !READER
//导入资料文件
this.CommandBindings.Add(new CommandBinding(Commands.ImportFilesToCategory, (sender, arg) => {
this.ShowDialog(new ImportFilesToCategoryWindow());
}));
//移动分类
this.CommandBindings.Add(new CommandBinding(Commands.MoveCategoryToCategory, MoveCategoryOrDocumentToCategoryCommandHandler));
//打开资料文件
this.CommandBindings.Add(new CommandBinding(Commands.OpenDocument, OpenDocumentCommandHandler));
//移动资料文件
this.CommandBindings.Add(new CommandBinding(Commands.MoveDocumentToCategory, MoveCategoryOrDocumentToCategoryCommandHandler));
//向资料中导入本地文件夹
this.CommandBindings.Add(new CommandBinding(Commands.ImportFolderToCategory, (sender, arg) => {
this.ShowDialog(new ImportFolderToCategoryWindow());
}));
//删除资料文件
this.CommandBindings.Add(new CommandBinding(Commands.DeleteDocument, DeleteDocumentCommandHandler));
//删除分类(仅分类)
this.CommandBindings.Add(new CommandBinding(Commands.DeleteCategory, DeleteCategoryCommandHandler));
//删除分类及下属文件
this.CommandBindings.Add(new CommandBinding(Commands.DeleteCategoryAndAll, DeleteCategoryAndAllCommandHandler));
#else
#endif
//打开发文
this.CommandBindings.Add(new CommandBinding(Commands.OpenSent, OpenSentCommandHandler));
//打开公文
this.CommandBindings.Add(new CommandBinding(Commands.OpenPaperWork, OpenPaperWorkCommandHandler));
//撤回公文
this.CommandBindings.Add(new CommandBinding(Commands.DeletePaperWork, DeletePaperWorkCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is PaperWork paperwork)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& paperwork.SendUnit != null && UnitHelper.IsMyUnit(paperwork.SendUnit.Code);
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//撤回素材
this.CommandBindings.Add(new CommandBinding(Commands.DeleteInformation, DeleteInformationCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Information information)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& information.SendUnit != null && UnitHelper.IsMyUnit(information.SendUnit.Code);
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//撤回通知
this.CommandBindings.Add(new CommandBinding(Commands.DeleteNotice, DeleteNoticeCommandHandler, (sender, e) => {
#if !READER
if (e.Parameter is Notice notice)
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
//&& (!product.IsLocked || product.LockerId == MainWindowViewModel.Current.Me.SN)
&& notice.SendUnit != null && UnitHelper.IsMyUnit(notice.SendUnit.Code);
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
//回复素材
this.CommandBindings.Add(new CommandBinding(Commands.ReplyInformation, (sender, arg) => {
NoticesViewModel.Current.ReplyingIntel = arg.Parameter as Information;
this.ShowDialog(new PostQuickWindow() {
OnManageReplyOptions = OnManageReplyOptions,
});
}, (sender, e) => {
#if !READER
if (e.Parameter is Information i && !(e.Parameter is Product))
{
e.CanExecute = (LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/
&& i.Receiver != null && UnitHelper.IsMyUnit(i.Receiver.ReceiveUnit));
}
else
{
e.CanExecute = false;
}
#else
e.CanExecute = false;
#endif
}));
this.CommandBindings.Add(new CommandBinding(Commands.RefreshImmediately, (sender, arg) => {
try
{
if (WindowMenu != null && WindowMenu.DataContext == null)
{
WindowMenu.DataContext = this.DataContext;
}
LogHelper.i("Update CommandManager in RefreshImmediately Command");
CommandManager.InvalidateRequerySuggested();
}
catch
{
}
new System.Threading.Tasks.Task(() => {
MainWindowViewModel.Current.RefrshSystemConfig();
}).Start();
MainWindowViewModel.Current.RefreshAll();
StatusBarViewModel.Current.DynamicMessage = "";
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
this.CommandBindings.Add(new CommandBinding(Commands.ResetDataVersion, (sender, arg) => {
//ver -= 1000;
//if (ver < 0) ver = 0;
//str = ver.ToString();
Models.Database.Database.Instance.ClearVersions();
MainWindowViewModel.Current.RefreshAll();
StatusBarViewModel.Current.DynamicMessage = "";
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
this.CommandBindings.Add(new CommandBinding(Commands.ResetDataBase, (sender, arg) => {
MessageBoxResult mbr = AyMessageBox.ShowQuestion("确定要重置数据库?", "重置数据库");
if (mbr != MessageBoxResult.Yes) { return; }
Models.Database.Database.Instance.Reset();
MainWindowViewModel.Current.Intels.Reset();
MainWindowViewModel.Current.RefreshAll();
StatusBarViewModel.Current.DynamicMessage = "";
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
this.CommandBindings.Add(new CommandBinding(Commands.RecreateDataBase, (sender, arg) => {
MessageBoxResult mbr = AyMessageBox.ShowQuestion("确定要重建数据库?", "重建数据库");
if (mbr != MessageBoxResult.Yes) { return; }
if (DBUtility.SQLite.SQLiteHelper.RecreateDb())
{
Models.Database.Database.Instance.Reset();
MainWindowViewModel.Current.Intels.Reset();
MainWindowViewModel.Current.RefreshAll();
StatusBarViewModel.Current.DynamicMessage = "";
ShowInformation("重建数据库成功!");
}
else ShowWarning("重建数据库失败!");
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
this.CommandBindings.Add(new CommandBinding(Commands.HistoryProduct, (sender, arg) => {
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示文件列表
this.CommandBindings.Add(new CommandBinding(Commands.ShowIntelsList, (sender, arg) => {
if (this.IntelsDrawer.Visibility == Visibility.Collapsed) {
this.IntelsDrawer.Visibility = Visibility.Visible;
} else {
this.IntelsDrawer.Visibility = Visibility.Collapsed;
}
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示待办事项窗口
this.CommandBindings.Add(new CommandBinding(Commands.ShowTodoes, (sender, arg) => {
this.ShowDialog(new TodoesWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示突发事件窗口
this.CommandBindings.Add(new CommandBinding(Commands.ShowIncidents, (sender, arg) => {
this.ShowDialog(new IncidentsWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示提醒窗口
this.CommandBindings.Add(new CommandBinding(Commands.ShowReminders, (sender, arg) => {
this.ShowDialog(new RemindersWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//显示优秀成果窗口
this.ShoExcellentsCommandHandler();
//显示即时消息
this.CommandBindings.Add(new CommandBinding(Commands.ShowFields, ShowFieldsCommandHandler, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//全文检索
this.CommandBindings.Add(new CommandBinding(Commands.FulltextSearch, FulltextSearchCommandHandler, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ && SearchViewModel.Current.CanFulltextSearch;
}));
//基于字段的检索
this.CommandBindings.Add(new CommandBinding(Commands.FieldsSearch, FieldsSearchCommandHandler, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/ && SearchViewModel.Current.CanFieldsSearch;
}));
//系统配置
this.CommandBindings.Add(new CommandBinding(Commands.SystemConfig, (sender, arg) => {
Timers.Suspend(Timers.TimerID.TimerRefreshTemplates);
ConfigViewModel.Current.WatchClassPropertyChanged(true);
ConfigWindow cfgWin = new ConfigWindow();
this.ShowDialog(cfgWin);
ConfigViewModel.Current.WatchClassPropertyChanged(false);
Timers.Resume(Timers.TimerID.TimerRefreshTemplates);
IntelsDrawer.FilterTabConfigChanged();
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//评价模板管理
this.CommandBindings.Add(new CommandBinding(Commands.EvalTempConfig, (sender, arg) => {
Timers.Suspend(Timers.TimerID.TimerEvaluationIndices);
EvaluateTemplateWindow win = new EvaluateTemplateWindow();
this.ShowDialog(win);
Timers.Resume(Timers.TimerID.TimerEvaluationIndices);
}, (sender, e) => {
#if !READER
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
#else
e.CanExecute = false;
#endif
}));
//值班查看
this.CommandBindings.Add(new CommandBinding(Commands.DutyConfig, (sender, arg) => {
this.ShowDialog(new ViewDutyWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//打印查看
this.CommandBindings.Add(new CommandBinding(Commands.PrintSearch, (sender, arg) => {
this.ShowDialog(new ViewPrintWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//查看日志
this.CommandBindings.Add(new CommandBinding(Commands.UserLogSearch, (sender, arg) => {
this.ShowDialog(new ViewLogsWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//热点推荐
this.RecommendSearchCommandHandler();
//特有推荐
this.InterestRecommendSearchCommandHandler();
//评价统计
this.CommandBindings.Add(new CommandBinding(Commands.EvaluateStat, (sender, arg) => {
this.ShowDialog(new ViewEvaluateStatWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//全屏编辑
this.CommandBindings.Add(new CommandBinding(Commands.FullScreenEdit, (sender, arg) => {
FullScreenEdit(true);
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined /*MainWindowViewModel.Current.Me.NetworkStatus == NetworkStatus.CONNECTED*/;
}));
//退出全屏编辑
this.CommandBindings.Add(new CommandBinding(Commands.ExitFullScreenEdit, (sender, arg) => {
FullScreenEdit(false);
}));
//显示统计详细信息
this.StatDetailsCommandHandler();
//显示统计分析信息
this.StatAnalysisCommandHandler();
//产品批量处理
this.CommandBindings.Add(new CommandBinding(Commands.ProductBatchCommand, (sender, arg) => {
ProductBatchWindow dialog = new ProductBatchWindow();//
dialog.Owner = this;
dialog.Closed += ProductBatchDialog_Closed;
dialog.Closed += Dialog_Closed;
ShowWindow(dialog);
Inteligences products = MainWindowViewModel.Current.Intels.Products;
foreach (IntelBase intel in products)
{
if (((Product)intel).IsDraft)
((Product)intel).IsDraftCheckVisible = true;
}
}, (sender, e) => {
#if !READER
e.CanExecute = MainWindowViewModel.Current.Intels.ProductDraftCount > 0;
#else
e.CanExecute = false;
#endif
}));
//素材标记采用
this.CommandBindings.Add(new CommandBinding(Commands.MarkAdoptCommand, (sender, arg) => {
IntelBase intel = null;
if (arg.Parameter is Information)
{
intel = arg.Parameter as Information;
}
if(arg.Parameter is PaperWork)
{
intel = arg.Parameter as PaperWork;
}
this.ShowDialog(new MarkAdoptWindow(intel));
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;
}));
//素材批量采用
this.CommandBindings.Add(new CommandBinding(Commands.BatchAdoptCommand, (sender, arg) => {
this.ShowWindow(new BatchAdoptWindow());
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;
}));
//取消标记采用
//this.CommandBindings.Add(new CommandBinding(Commands.CancelMarkAdoptCommand, (sender, arg) => {
// Information information = arg.Parameter as Information;
// if (information == null) return;
// this.Waiting("正在取消采用标记...", true, true);
// ServiceApi.DeleteIntelAdoptDetail(information, (errno, message) => {
// if(errno != Zonkin.IPP.V1.Base.ErrorNo.ErrSuccess)
// {
// this.CancelWaiting();
// this.ForceCancelWaiting();
// ShowWarning("取消采用标记失败:" + message);
// }
// else
// {
// this.CancelWaiting("取消采用标记成功!", true);
// this.ForceCancelWaiting();
// }
// });
//}, (sender, e) => {
// e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;
//}));
//报表上报
this.CommandBindings.Add(new CommandBinding(Commands.ReportIntelCammend, (sender, arg) => {
if (!ReportIntelWindowViewModel.Current.IsShowing)
{
Point point = this.IndicatorControls.TranslatePoint(new Point(-400, IndicatorControls.ActualHeight), this);
ReportIntelWindow reportIntelWindow = new ReportIntelWindow()
{
Left = point.X,
Top = point.Y,
createReportIntelProductHandler = CreateReportIntelProductCommandHandler,
openReportIntelHandler = OpenReportIntelHandler,
mergeReportIntelHandler = MergeReportIntelInformationCommandHandler,
unlockReportIntelProductHandler = UnlockReportIntelHandler,
deleteReportIntelProduct = DeleteReportIntelProductCommandHandler,
convertNewReportProductHandler = ConvertNewReportProductCommandHandler
};
reportIntelWindow.Owner = this;
//this.ShowWindow(reportIntelWindow);
reportIntelWindow.Show();
}
}, (sender, e) => {
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;
}));
//态势展示
IncidentMapWindowHelper.InitializeParentCommandHandlers(this);
//在线状态
this.CommandBindings.Add(new CommandBinding(Commands.LoginStatus, (sender, arg) =>
{
LoginStatusWindow win = new LoginStatusWindow();
this.ShowWindow(win);
//BrowserHelper.OpenBrowserUrl(Webpages.GetUrl(Webpages.LOGIN_STATUS) + "?sn=" + Config.SN);
}, (sender, e) =>
{
e.CanExecute = LongLink.LongLinkViewModel.Current.AppState == LongLink.AppState.Logined;
}));
//实施升级
this.CommandBindings.Add(new CommandBinding(Commands.UpdateCommand, DoUpdate));
}
有关Model(模型)和DTO的问题
前面说的Model是客户端的,但实际上Domail Model存在服务器端(靠近数据库)和那就需要和客户端搞映射DTO(Data Transfer Ojbect,数据传输对象,带序列化标记,用来远程调用)。在Silverlight中有个很方便的东西来实现这个DTO过程和序列化,那就是WCF RIA Service和DomainService。如果你创建一个简单的Silverlight应用并且调用WCF RIA Service,基本上会生成DTO Model: ObjectContext(EntityObject)。
MVVM的实践要点
1. View分离要彻底,不要有坏味道
视图(view)部分,xaml.cs 应该只有很少的代码或没有代码,如果你的xaml.cs包含大量的代码,那么很可能你MVVM用的不对头,需要检查其中代码的坏味道。Xaml和xaml.cs 只能包含处理界面、视图、显示样式、视图元素之间的交互、视图元素动画,等等的内容。
2. ViewModel要可测试
从重构的观点看,如果你的代码中ViewModel是可测试的,有详细的单元测试Unit Test,你的代码是OK的,否则需要检查其中的坏味道。