wpf - 使用 XML 设置序列化实现消息抑制系统
问题描述
在我的应用程序中,我需要一个系统,其中向用户显示的某些消息具有“不再显示”复选框。在“设置”菜单中,我希望有一个“已关闭消息”部分,其中包含消息名称和每个复选框,以便用户可以在需要时取消关闭它们。如果消息被关闭,则在消息对话框中选择的最后一个选择用户应成为默认选择。
此外,设置应保存到 XML 文件中 - 包括消息抑制状态和默认选项。我目前的解决方案非常粗糙,我想知道是否有更好的方法。
消息类定义为:
Public Class Message
Public Property title As String
Public Property content As String
Public Property buttons As Utilities.Enums.messageButtonTypes 'Ok/Cancel, Yes/No, etc.
Public Property allowDoNotShowAgain As Boolean = False 'whether the message is dismissable
Public Property doNotShowAgain As Boolean = False 'the actual dismiss state
Public Property result As Boolean
Public Property rememberedResult As Boolean 'last user choice if the message is dismissed
End Class
具体消息在MSG模块中初始化:
Module Msg
'This message is not dismissable
Public connectionNotEstablished As New Message() With {
.title = "Connection not established",
.content = "Connection not established. Please check if the host application is running.",
.buttons = Utilities.Enums.messageButtonTypes.Ok
}
'This message is dismissable
Public noResultsPlotsDefined As New Message() With {
.title = "No plots defined",
.content = "You have not defined any plots. Would you like to run the study anyway?",
.buttons = Utilities.Enums.messageButtonTypes.YesNo,
.allowDoNotShowAgain = True
}
'Just a list to store references to all the messages for binding, looping, etc.
Public allMessages As New List(Of Message) From {
connectionNotEstablished,
noResultsPlotsDefined
}
Public Function ShowMessage(message As Message) As Boolean
If message.doNotShowAgain Then message.result = message.rememberedResult : Return message.rememberedResult 'If message is dismissed, return the last user choice
Dim messageDialog As New MessageDialog(message.title, message.content, message.buttons, message.allowDoNotShowAgain, message.defaultButtonCustomCaption, message.cancelButtonCustomCaption)
message.result = messageDialog.ShowDialog()
message.doNotShowAgain = messageDialog.doNotShowAgain
If message.doNotShowAgain Then message.rememberedResult = message.result
Return message.result
End Function
End Module
在各种函数中调用特定的消息,例如,像这样:
Msg.ShowMessage(connectioNotEstablished)
到目前为止,这很容易——在构建我的应用程序时使用起来非常方便。现在,我不确定的一点 - AppSettings 类。就像我说的,我需要存储每条消息的一些属性,以便我可以 WPF 绑定到设置窗口中的消息列表。现在,AppSettings 引用了 MSG 类消息列表:
Public Class AppSettings
Public Property messages As List(Of Message) = Msg.allMessages
Public Sub SaveToDefaultPath()
Save(Constants.Paths.settingsFilePath)
End Sub
Private Sub Save(ByVal filename As String)
Using sw As StreamWriter = New StreamWriter(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
xmls.Serialize(sw, Me)
End Using
End Sub
Private Function Read(ByVal filename As String) As AppSettings
Using sw As StreamReader = New StreamReader(filename)
Dim xmls As XmlSerializer = New XmlSerializer(GetType(AppSettings))
Return TryCast(xmls.Deserialize(sw), AppSettings)
End Using
End Function
End Class
在我的设置 WPF 窗口中,我可以绑定到该messages
属性,并选择将其显示title
为 TextBlock、doNotShowAgain
CheckBox 和rememberedResult
ComboBox。我还没有做那一点,但我认为对于当前的应用程序架构应该非常简单。
问题是 XML 的序列化和反序列化(参见AppSettings
类的最后两个函数)。由于此类存储对整个消息列表的引用,该列表不仅具有title
,doNotShowAgain
和rememberedResult
,而且还具有消息内容及其其他属性,这确实使 XML 文件变得混乱。
我不知道如何解决这个问题。也许,我可以只将每条消息的所需变量存储在 中AppSettings
,但这需要某种双向转换器或其他东西。至此,我开始怀疑这是否真的是实现我所需要的正确方法。
我不能成为第一个实现这一点的人,所以也许有这样的约定。有什么建议么?
编辑:在等待答案时,我已成功实现将消息解除状态保存到 XML - 不幸的是,它保存了整个message
类数据,而不仅仅是title
,doNotShowAgain
和rememberedResult
. 为了完成这项工作,我只需要做一个小改动——inmessages
中的属性AppSettings
被声明为一个数组而不是一个列表,因此 XML 反序列化器不会将消息附加到该列表,而是将其替换为整个。
Public Class AppSettings
Public Property Messages() As Message() = Msg.allMessages.ToArray()
...
End Class
因此,虽然这有效(将这些绑定messages
到 WPF 窗口也有效),但 XML 文件中充斥着每条消息的不必要值,例如:
<Message>
<title>No plots defined</title>
<content>You have not defined any plots. Would you like to run the study anyway?</content>
<buttons>YesNo</buttons>
<allowDoNotShowAgain>true</allowDoNotShowAgain>
<doNotShowAgain>false</doNotShowAgain>
<result>false</result>
<rememberedResult>false</rememberedResult>
</Message>
但是对于这个用例,对于 XML 文件中的每条消息来说,只有这个位就足够了:
<Message>
<title>No plots defined</title>
<doNotShowAgain>false</doNotShowAgain>
<rememberedResult>false</rememberedResult>
</Message>
所以我的问题仍然存在 - 这里最好的解决方案是什么?我什至在球场上?
解决方案
看来您唯一的问题是 Xml 文件中存在混乱。所以你可以告诉序列化程序忽略某些属性<XmlIgnore>
Public Class Message
Public Property title As String
<XmlIgnore>
Public Property content As String
<XmlIgnore>
Public Property buttons As Utilities.Enums.messageButtonTypes 'Ok/Cancel, Yes/No, etc.
<XmlIgnore>
Public Property allowDoNotShowAgain As Boolean = False 'whether the message is dismissable
Public Property doNotShowAgain As Boolean = False 'the actual dismiss state
<XmlIgnore>
Public Property result As Boolean
Public Property rememberedResult As Boolean 'last user choice if the message is dismissed
End Class
序列化程序既不会序列化也不会反序列化这些属性。
现在您还可以序列化 linq 查询定义的消息子集,如下所示
<XmlIgnore>
Public Property messages As List(Of Message) = Msg.allMessages
<XmlElement("messages")>
Public Property messagesAllowDoNotShowAgain As List(Of Message) = Msg.allMessages.Where(Function(m) m.allowDoNotShowAgain).ToList()
推荐阅读
- eloquent - 如何避免 Laravel Eloquent 对具有双向对象关联的同一实体重复数据库获取?
- python - 根据索引替换列表中的项目
- javascript - 自动登录不触发事件?
- python - 修改函数内部的列表
- javascript - Concat 方法返回空字符串,而 + 运算符工作正常
- msal-angular - 将 MSAL 用于 Angular 和 NGXLogger
- bash - MotioneyeOS bash 脚本来调整 raspimjpeg 设置
- matlab - Matlab中的矩阵方程求解
- go - 为什么定向通道切片无法编译?
- kubernetes - Airflow Kubernetes Pods 异常错误 - (404) 原因:未找到