实现设置序列化为 XML 的消息抑制系统
Implementing a message suppression system with settings serialization to XML
在我的应用程序中,我需要一个系统,其中显示给用户的某些消息具有“不再显示”复选框。在“设置”菜单中,我希望有一个“已关闭的消息”部分,其中包含消息名称和每个消息的复选框,以便用户可以在需要时取消关闭它们。如果消息被关闭,用户在消息对话框中选择的最后一个选项应该成为默认选项。
此外,设置应保存到 XML 文件中 - 包括消息抑制状态和默认选择。我目前的解决方案很粗糙,想知道有没有更好的方法。
消息class定义为:
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 class。正如我所说,我需要存储每条消息的一些属性,以便我可以 WPF 绑定到设置 window 中的消息列表。现在,AppSettings 引用了 MSG class 消息列表:
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 window 中,然后我可以绑定到 messages
属性,并选择将 title
显示为 TextBlock,doNotShowAgain
作为复选框,rememberedResult
作为组合框。我还没有这样做,但我认为对于当前的应用程序体系结构来说应该非常简单。
问题出在 XML 的序列化和反序列化(参见 AppSettings
class 的最后两个函数)。因为这个 class 存储了对整个消息列表的引用,它不仅有 title
、doNotShowAgain
和 rememberedResult
,还有消息内容和它的其他属性,这真的XML 文件混乱。
我不知道如何解决这个问题。也许我可以只将每条消息所需的变量存储在 AppSettings
中,但这需要某种双向转换器或其他东西。至此,我开始怀疑这是否真的是实现我所需的正确方法。
我不是第一个实现它的人,所以也许有这样的约定。有什么建议吗?
编辑:在等待答案时,我已经成功实现了将消息关闭状态保存到 XML - 不幸的是,它保存了整个 message
class 数据,而不仅仅是 title
、doNotShowAgain
和 rememberedResult
。为了完成这项工作,我只需要做一个小改动——AppSettings
中的 属性 messages
被声明为数组而不是列表,因此 XML反序列化器不会将消息附加到该列表,而是将其作为一个整体替换。
Public Class AppSettings
Public Property Messages() As Message() = Msg.allMessages.ToArray()
...
End Class
因此,虽然这有效(将这些 messages
绑定到 WPF window 也有效),但 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()
在我的应用程序中,我需要一个系统,其中显示给用户的某些消息具有“不再显示”复选框。在“设置”菜单中,我希望有一个“已关闭的消息”部分,其中包含消息名称和每个消息的复选框,以便用户可以在需要时取消关闭它们。如果消息被关闭,用户在消息对话框中选择的最后一个选项应该成为默认选项。
此外,设置应保存到 XML 文件中 - 包括消息抑制状态和默认选择。我目前的解决方案很粗糙,想知道有没有更好的方法。
消息class定义为:
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 class。正如我所说,我需要存储每条消息的一些属性,以便我可以 WPF 绑定到设置 window 中的消息列表。现在,AppSettings 引用了 MSG class 消息列表:
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 window 中,然后我可以绑定到 messages
属性,并选择将 title
显示为 TextBlock,doNotShowAgain
作为复选框,rememberedResult
作为组合框。我还没有这样做,但我认为对于当前的应用程序体系结构来说应该非常简单。
问题出在 XML 的序列化和反序列化(参见 AppSettings
class 的最后两个函数)。因为这个 class 存储了对整个消息列表的引用,它不仅有 title
、doNotShowAgain
和 rememberedResult
,还有消息内容和它的其他属性,这真的XML 文件混乱。
我不知道如何解决这个问题。也许我可以只将每条消息所需的变量存储在 AppSettings
中,但这需要某种双向转换器或其他东西。至此,我开始怀疑这是否真的是实现我所需的正确方法。
我不是第一个实现它的人,所以也许有这样的约定。有什么建议吗?
编辑:在等待答案时,我已经成功实现了将消息关闭状态保存到 XML - 不幸的是,它保存了整个 message
class 数据,而不仅仅是 title
、doNotShowAgain
和 rememberedResult
。为了完成这项工作,我只需要做一个小改动——AppSettings
中的 属性 messages
被声明为数组而不是列表,因此 XML反序列化器不会将消息附加到该列表,而是将其作为一个整体替换。
Public Class AppSettings
Public Property Messages() As Message() = Msg.allMessages.ToArray()
...
End Class
因此,虽然这有效(将这些 messages
绑定到 WPF window 也有效),但 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()