WPF MaterialDesignInXamlToolkit:如何为不同类型的Snackbar消息设置差异化样式?
这个问题我之前也碰到过,你的初始方案的核心问题在于:SnackBar的样式是绑定到ViewModel的全局属性MessageQueueType,而消息队列里的所有消息都会共享这个属性的值——当你添加新消息时更新这个属性,所有待显示的消息都会跟着用最新的样式,这就是为什么所有消息都变成最后那个类型的样式了。
不用创建多个SnackBar和队列,我们可以让每个消息自己携带样式信息,通过自定义模板实现不同消息的差异化样式,这是更优雅的解决方案:
优化方案:让每个消息携带自身样式标识
1. 创建自定义消息模型
首先定义一个类,把消息内容和状态打包在一起,让每个消息都有自己的类型标识:
public class StyledSnackbarMessage { public string Content { get; set; } public MessageQueueStatus Status { get; set; } }
(假设你的MessageQueueStatus枚举已经包含Error/Info/Success这几个值)
2. 更新ViewModel的消息发送逻辑
修改ShowSnackMessage方法,把自定义的消息对象加入队列,不再依赖全局的MessageQueueType属性:
private void ShowSnackMessage(string message, MessageQueueStatus messageQueueType, bool ClearOtherMessages = false) { if(ClearOtherMessages) MessageQueue.Clear(); // 将消息内容和状态打包成自定义对象入队 MessageQueue.Enqueue(new StyledSnackbarMessage { Content = message, Status = messageQueueType }); }
3. 自定义SnackBar的消息模板
在XAML中给MainSnackbar设置DataTemplate,让它根据每个消息的Status属性动态应用样式:
<materialDesign:Snackbar x:Name="MainSnackbar" Grid.Row="0" HorizontalAlignment="Center" ActionButtonPlacement="Inline" MessageQueue="{Binding MessageQueue}"> <materialDesign:Snackbar.DataTemplate> <DataTemplate DataType="{x:Type local:StyledSnackbarMessage}"> <Border x:Name="SnackbarContainer" Padding="16" CornerRadius="4"> <TextBlock Text="{Binding Content}" Foreground="{Binding Status, Converter={StaticResource StatusToMessageForegroundColorConverter}}"/> </Border> <DataTemplate.Triggers> <!-- 根据消息状态设置背景色 --> <DataTrigger Binding="{Binding Status}" Value="Error"> <Setter TargetName="SnackbarContainer" Property="Background" Value="#8B0000"/> </DataTrigger> <DataTrigger Binding="{Binding Status}" Value="Info"> <Setter TargetName="SnackbarContainer" Property="Background" Value="#696969"/> </DataTrigger> <DataTrigger Binding="{Binding Status}" Value="Success"> <Setter TargetName="SnackbarContainer" Property="Background" Value="#228B22"/> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </materialDesign:Snackbar.DataTemplate> </materialDesign:Snackbar>
如果你想继续使用之前的转换器,也可以直接把Border的Background绑定到Status:
<Border Background="{Binding Status, Converter={StaticResource StatusToMessageBackgroundColorConverter}}" ...>
4. 移除全局样式绑定
记得删掉原来SnackBar上的Background和Foreground绑定,现在样式由每个消息的模板独立控制,不再依赖ViewModel的全局属性。
这样修改后,每个消息都会根据自身携带的Status显示对应的样式,不管队列里有多少不同类型的消息,都能正确渲染各自的样式,而且只需要一个SnackBar和一个队列,比多实例方案简洁得多。
内容的提问来源于stack exchange,提问作者Rafael Leonardi
相关产品推荐
相关产品推荐

