You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI如何在底部Tab图标上动态显示未读消息数字(MVVM)

实现Shell消息Tab的动态未读角标(MVVM架构)

1. 定义ViewModel的未读消息属性

先写一个基础ViewModel基类,处理属性变化通知:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

再在消息页对应的ViewModel里添加未读消息数相关属性:

public class MessagesViewModel : BaseViewModel
{
    private int _unreadMessageCount;
    public int UnreadMessageCount
    {
        get => _unreadMessageCount;
        set
        {
            _unreadMessageCount = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(HasUnreadMessages));
        }
    }

    public bool HasUnreadMessages => UnreadMessageCount > 0;

    // 实际项目里替换成接口回调/消息推送的逻辑
    public void UpdateUnreadCount(int count)
    {
        UnreadMessageCount = count;
    }
}

2. 自定义带角标的Tab视图

创建一个TabBadgeView,把图标和角标整合到一起:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourApp.Views.TabBadgeView">
    <RelativeLayout>
        <!-- 消息图标 -->
        <Image x:Name="IconImage"
               RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width}"
               RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height}"/>
        <!-- 未读角标 -->
        <Label x:Name="BadgeLabel"
               Text="{Binding UnreadMessageCount}"
               IsVisible="{Binding HasUnreadMessages}"
               BackgroundColor="#FF3B30"
               TextColor="White"
               FontSize="Micro"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center"
               CornerRadius="10"
               Padding="6,2"
               RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.6}"
               RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.1}"/>
    </RelativeLayout>
</ContentView>

后台代码绑定图标属性:

public partial class TabBadgeView : ContentView
{
    public static readonly BindableProperty IconProperty = BindableProperty.Create(nameof(Icon), typeof(ImageSource), typeof(TabBadgeView));
    public ImageSource Icon
    {
        get => (ImageSource)GetValue(IconProperty);
        set => SetValue(IconProperty, value);
    }

    public TabBadgeView()
    {
        InitializeComponent();
        IconImage.SetBinding(Image.SourceProperty, new Binding(nameof(Icon), source: this));
    }
}

3. 修改Shell的Tab配置

把原来的Tab图标替换成自定义的TabBadgeView,并绑定ViewModel属性:

<Tab Title="Inbox" x:Name="messages">
    <Tab.Icon>
        <local:TabBadgeView Icon="message.svg"
                            BindingContext="{Binding Source={RelativeSource AncestorType={x:Type viewModels:MessagesViewModel}}}"/>
    </Tab.Icon>
    <ShellContent ContentTemplate="{DataTemplate views:MessagesPage}" Route="messages"/>
</Tab>

如果Shell有全局ViewModel,也可以绑定全局的未读属性:

<local:TabBadgeView Icon="message.svg"
                    BindingContext="{Binding Source={RelativeSource AncestorType={x:Type viewModels:AppShellViewModel}}}"
                    UnreadMessageCount="{Binding MessagesUnreadCount}"
                    HasUnreadMessages="{Binding HasUnreadMessages}"/>

4. 更新未读消息数

在需要更新未读数的场景(比如消息推送回调、接口请求完成后),调用ViewModel的更新方法:

// 示例:消息服务回调中更新未读数
var messagesVm = (MessagesViewModel)MessagesPage.BindingContext;
messagesVm.UpdateUnreadCount(2); // 设置为2条未读

内容的提问来源于stack exchange,提问作者user1066231

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 13:10:23