WPF 自定义TextBox(WPF带图片,占位符,清除按钮的TextBox)改造版

本文介绍了一种自定义 WPF 控件 ImageTextBox 的实现方法,该控件集成了图片显示、占位符文本、清除按钮及扩展图标等功能,并提供了丰富的自定义属性。通过 XAML 和 C# 的结合使用,实现了灵活的布局和交互效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果:



Style:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ctrls="clr-namespace:ImageButtonTest01.Control"
    xmlns:converter="clr-namespace:ImageButtonTest01.Control.Converter">


    <converter:ImageTextBoxMarginLeftConverter x:Key="ITBMLC"/>
    <converter:PlaceholderFontSizeConverter x:Key="PHFSC"/>


    <SolidColorBrush x:Key="ImageTextBox.Static.BorderBrush" Color="#FF909090"/>
    <SolidColorBrush x:Key="ImageTextBox.Focused.BorderBrush" Color="#FF007ACC"/>
    <SolidColorBrush x:Key="ImageTextBox.MouseOver.BorderBrush" Color="#FF1E1E1E"/>


    <Style TargetType="{x:Type ctrls:ImageTextBox}">
        <Setter Property="Foreground" Value="Black"/>
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="{StaticResource ImageTextBox.Focused.BorderBrush}"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="CaretBrush" Value="Black"/>
        <Setter Property="Opacity" Value="1"/>
        <Setter Property="CornerRadius" Value="0"/>
        <Setter Property="FontSize" Value="18"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ctrls:ImageTextBox}">
                    <Border x:Name="border"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                            CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}}">


                        <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ITBMLC}}"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>


                            <Image x:Name="PART_ContentIdentity" Grid.Column="1" Margin="0" Stretch="Uniform"
                                   Width="{Binding LeftImageWidth, RelativeSource={RelativeSource TemplatedParent}}"
                                   Height="{Binding LeftImageWidth, RelativeSource={RelativeSource TemplatedParent}}"
                                   Source="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"
                                   HorizontalAlignment="Center" VerticalAlignment="Center"/>


                            <ScrollViewer x:Name="PART_ContentHost" Grid.Column="2" IsTabStop="False" Margin="2,0,2,0"
                                          Focusable="false" Background="Transparent" SnapsToDevicePixels="True"
                                          HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"
                                          HorizontalAlignment="Stretch" VerticalAlignment="Center"
                                          FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}}"
                                          Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
                                          HorizontalContentAlignment="Left"/>


                            <TextBlock x:Name="PART_PlaceHolder" Grid.Column="2" IsHitTestVisible="False" Margin="3,0,3,0"
                                       HorizontalAlignment="Left" VerticalAlignment="Center"
                                       SnapsToDevicePixels="True"
                                       Visibility="Collapsed" Opacity="0.6"
                                       TextAlignment="{TemplateBinding TextAlignment}"
                                       Text="{Binding Path=PlaceHolder, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                       FontSize="{Binding FontSize, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource PHFSC}}"/>


                            <ctrls:ImageButton x:Name="PART_ClearTextButton" Grid.Column="3" Margin="2" IsTabStop="False"
                                               FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
                                               Content="&#xe63c;" FontSize="20"
                                               HorizontalAlignment="Right"
                                               VerticalAlignment="Center"
                                               Style="{StaticResource ImageButtonTransparent}"/>


                            <ctrls:ImageButton x:Name="PART_ExtendIconFontButton" Grid.Column="4" FontSize="20"
                                               HorizontalAlignment="Center" VerticalAlignment="Center"
                                               FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
                                               Content="{Binding ExtendIconFontText, RelativeSource={RelativeSource TemplatedParent}}"
                                               Style="{StaticResource ImageButtonTransparent}"
                                               Command="{Binding ExtendButtonCommand, RelativeSource={RelativeSource TemplatedParent}}"
                                               CommandParameter="{Binding ExtendButtonCommandParameter, RelativeSource={RelativeSource TemplatedParent}}"
                                               CommandTarget="{Binding ExtendButtonCommandTarget, RelativeSource={RelativeSource TemplatedParent}}"/>


                            <ctrls:ImageButton x:Name="PART_ExtendImageButton" Grid.Column="5"
                                               HorizontalAlignment="Center" VerticalAlignment="Center"
                                               FontFamily="/ImageButtonTest01;component/Resources/#iconfont"
                                               NormalImage="{Binding ExtendNormalImage, RelativeSource={RelativeSource TemplatedParent}}"
                                               HoverImage="{Binding ExtendHoverImage, RelativeSource={RelativeSource TemplatedParent}}"
                                               PressedImage="{Binding ExtendPressedImage, RelativeSource={RelativeSource TemplatedParent}}"
                                               DisabledImage="{Binding ExtendDisabledImage, RelativeSource={RelativeSource TemplatedParent}}"
                                               Style="{StaticResource ImageButtonTransparent}"
                                               Command="{Binding ExtendButtonCommand, RelativeSource={RelativeSource TemplatedParent}}"
                                               CommandParameter="{Binding ExtendButtonCommandParameter, RelativeSource={RelativeSource TemplatedParent}}"
                                               CommandTarget="{Binding ExtendButtonCommandTarget, RelativeSource={RelativeSource TemplatedParent}}"/>
                        </Grid>
                    </Border>


                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=ExtendNormalImage, RelativeSource={RelativeSource Mode=Self}}" Value="{x:Null}">
                            <Setter TargetName="PART_ExtendImageButton" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>


                        <DataTrigger Binding="{Binding Path=ExtendIconFontText, RelativeSource={RelativeSource Mode=Self}}" Value="">
                            <Setter TargetName="PART_ExtendIconFontButton" Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>


                        <DataTrigger Binding="{Binding Path=Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
                            <Setter TargetName="PART_PlaceHolder" Property="Visibility" Value="Visible"/>
                            <Setter TargetName="PART_ClearTextButton" Property="IsEnabled" Value="False"/>
                            <Setter TargetName="PART_ExtendIconFontButton" Property="IsEnabled" Value="False"/>
                            <Setter TargetName="PART_ExtendImageButton" Property="IsEnabled" Value="False"/>
                        </DataTrigger>


                        <Trigger Property="IsFocused" Value="False">
                            <Setter TargetName="border" Property="BorderBrush" Value="{StaticResource ImageTextBox.Static.BorderBrush}"/>
                        </Trigger>


                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="border" Property="BorderBrush" Value="{StaticResource ImageTextBox.MouseOver.BorderBrush}"/>
                        </Trigger>


                        <Trigger Property="IsReadOnly" Value="True">
                            <Setter TargetName="PART_ClearTextButton" Property="IsEnabled" Value="False"/>
                            <Setter Property="Opacity" Value="0.6" TargetName="border" />
                        </Trigger>


                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Opacity" Value="0.5" TargetName="border" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

C#

ImageTextBox.CS

public class ImageTextBox : TextBox
{
    private ImageButton mClearTextButton = null;
    private ImageButton mExtendIconFontButton = null;
    private ImageButton mExtendImageButton = null;


    static ImageTextBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageTextBox), new FrameworkPropertyMetadata(typeof(ImageTextBox)));
    }


    public ImageTextBox()
    {
            
    }


    public override void OnApplyTemplate()
    {
        mClearTextButton = GetTemplateChild("PART_ClearTextButton") as ImageButton;
        if (null != mClearTextButton)
        {
            mClearTextButton.Click += OnClearTextClick;
        }


        mExtendIconFontButton = GetTemplateChild("PART_ExtendIconFontButton") as ImageButton;
        if (null != mExtendIconFontButton)
        {
            mExtendIconFontButton.Click += ExtendButtonClick;
        }


        mExtendImageButton = GetTemplateChild("PART_ExtendImageButton") as ImageButton;
        if (null != mExtendIconFontButton)
        {
            mExtendImageButton.Click += ExtendButtonClick;
        }


        base.OnApplyTemplate();
    }


    private void ExtendButtonClick(object sender, RoutedEventArgs e)
    {
        RoutedEventArgs re = new RoutedEventArgs(ImageTextBox.ExtendClickEvent, this);
        RaiseEvent(re);
    }


    private void OnClearTextClick(object sender, RoutedEventArgs e)
    {
        if (sender is ImageButton)
        {
            Text = "";
        }
    }


    public static readonly DependencyProperty ImageProperty = DependencyProperty.Register(nameof(Image), typeof(ImageSource), typeof(ImageTextBox),
                                                                                            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, ImageSourceChanged));
    public ImageSource Image
    {
        get { return (ImageSource)GetValue(ImageProperty); }
        set { SetValue(ImageProperty, value); }
    }


    public static readonly DependencyProperty ExtendNormalImageProperty = DependencyProperty.Register(nameof(ExtendNormalImage), typeof(ImageSource), typeof(ImageTextBox),
                                                                                    new FrameworkPropertyMetadata(null));
    public ImageSource ExtendNormalImage
    {
        get { return (ImageSource)GetValue(ExtendNormalImageProperty); }
        set { SetValue(ExtendNormalImageProperty, value); }
    }


    public static readonly DependencyProperty ExtendHoverImageProperty = DependencyProperty.Register(nameof(ExtendHoverImage), typeof(ImageSource), typeof(ImageTextBox),
                                                                                    new FrameworkPropertyMetadata(null));
    public ImageSource ExtendHoverImage
    {
        get { return (ImageSource)GetValue(ExtendHoverImageProperty); }
        set { SetValue(ExtendHoverImageProperty, value); }
    }


    public static readonly DependencyProperty ExtendPressedImageProperty = DependencyProperty.Register(nameof(ExtendPressedImage), typeof(ImageSource), typeof(ImageTextBox),
                                                                                    new FrameworkPropertyMetadata(null));
    public ImageSource ExtendPressedImage
    {
        get { return (ImageSource)GetValue(ExtendPressedImageProperty); }
        set { SetValue(ExtendPressedImageProperty, value); }
    }


    public static readonly DependencyProperty ExtendDisabledImageProperty = DependencyProperty.Register(nameof(ExtendDisabledImage), typeof(ImageSource), typeof(ImageTextBox),
                                                                                    new FrameworkPropertyMetadata(null));
    public ImageSource ExtendDisabledImage
    {
        get { return (ImageSource)GetValue(ExtendDisabledImageProperty); }
        set { SetValue(ExtendDisabledImageProperty, value); }
    }


    public static readonly DependencyProperty PlaceHolderProperty = DependencyProperty.Register(nameof(PlaceHolder), typeof(string), 
                                                                typeof(ImageTextBox), new PropertyMetadata(""));
    public string PlaceHolder
    {
        get { return (string)GetValue(PlaceHolderProperty); }
        set { SetValue(PlaceHolderProperty, value); }
    }


    public static readonly DependencyProperty ExtendIconFontTextProperty = DependencyProperty.Register(nameof(ExtendIconFontText), typeof(string),
                                                                typeof(ImageTextBox), new PropertyMetadata(""));
    public string ExtendIconFontText
    {
        get { return (string)GetValue(ExtendIconFontTextProperty); }
        set { SetValue(ExtendIconFontTextProperty, value); }
    }


    public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius), typeof(CornerRadius), 
        typeof(ImageTextBox), new PropertyMetadata(new CornerRadius(0,0,0,0)));
    public CornerRadius CornerRadius
    {
        get { return (CornerRadius)GetValue(CornerRadiusProperty); }
        set { SetValue(CornerRadiusProperty, value); }
    }


    public static readonly DependencyProperty LeftImageWidthProperty = DependencyProperty.Register(nameof(LeftImageWidth), typeof(double),
                                                                                    typeof(ImageTextBox), new PropertyMetadata(0.0));
    public double LeftImageWidth
    {
        get { return (double)GetValue(LeftImageWidthProperty); }
        set { SetValue(LeftImageWidthProperty, value); }
    }


    private static void ImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        ImageTextBox itb = sender as ImageTextBox;
        ImageSource image = e.NewValue as ImageSource;


        itb.SetValue(LeftImageWidthProperty, image.Width);
    }


    public static readonly RoutedEvent ExtendClickEvent = EventManager.RegisterRoutedEvent(nameof(ExtendClick), RoutingStrategy.Bubble,
                                                                        typeof(RoutedEventHandler), typeof(ImageTextBox));


    public event RoutedEventHandler ExtendClick
    {
        add { AddHandler(ExtendClickEvent, value); }
        remove { RemoveHandler(ExtendClickEvent, value); }
    }


    public static DependencyProperty ExtendButtonCommandProperty = DependencyProperty.Register(nameof(ExtendButtonCommand), typeof(ICommand), typeof(ImageTextBox));
    public ICommand ExtendButtonCommand
    {
        get { return (ICommand)GetValue(ExtendButtonCommandProperty); }
        set { SetValue(ExtendButtonCommandProperty, value); }
    }


    public static readonly DependencyProperty ExtendButtonCommandParameterProperty =
                                    DependencyProperty.Register(nameof(ExtendButtonCommandParameter), typeof(object), typeof(ImageTextBox), new UIPropertyMetadata(null));
    public object ExtendButtonCommandParameter
    {
        get { return (object)GetValue(ExtendButtonCommandParameterProperty); }
        set { SetValue(ExtendButtonCommandParameterProperty, value); }
    }


    public static readonly DependencyProperty ExtendButtonCommandTargetProperty =
                                DependencyProperty.Register(nameof(ExtendButtonCommandTarget), typeof(IInputElement), typeof(ImageTextBox), new UIPropertyMetadata(null));
    public IInputElement ExtendButtonCommandTarget
    {
        get { return (IInputElement)GetValue(ExtendButtonCommandTargetProperty); }
        set { SetValue(ExtendButtonCommandTargetProperty, value); }
    }
}

转换器ImageTextBoxMarginLeftConverter.cs

public class ImageTextBoxMarginLeftConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double)
        {
            double v = (double)value;
            return v * 3.0 / 5.0;
        }
        return 0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}


使用:

<StackPanel Orientation="Vertical" Grid.Row="1">
    <control:ImageTextBox x:Name="tbUserName" Width="200" Height="50" FontSize="30" Margin="5"
                        CornerRadius="12"
                        PlaceHolder="请输入用户名"
                        ExtendIconFontText="&#xe6d6;"
                        ExtendNormalImage="Resources/Images/MS.png"
                        ExtendHoverImage="Resources/Images/MS.png"
                        ExtendPressedImage="Resources/Images/MS.png"
                        ExtendDisabledImage="Resources/Images/MS.png"
                        Text="{Binding InputText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        ExtendButtonCommand="{Binding BottonCommand}" ExtendButtonCommandParameter="button1 Click"/>
    <control:ImageTextBox x:Name="tbUserName1" Width="200" Height="50" Margin="5"
                        ExtendIconFontText="&#xe6d6;"
    CornerRadius="20" FontSize="20" Background="YellowGreen"
    PlaceHolder="请输入用户名"/>
    <control:ImageTextBox x:Name="tbUserName2" Width="200" Height="50" Margin="5"
                        ExtendNormalImage="Resources/Images/MS.png"
                        ExtendHoverImage="Resources/Images/MS.png"
                        ExtendPressedImage="Resources/Images/MS.png"
                        ExtendDisabledImage="Resources/Images/MS.png"
    PlaceHolder="请输入用户名"
    Image="Resources/Images/logo.png"/>
    <control:ImageTextBox x:Name="tbUserName3" Width="200" Height="50" Margin="5"
    PlaceHolder="请输入用户名" CornerRadius="20" IsEnabled="True"
    Image="Resources/Images/logo.png"/>
    <control:ImageTextBox x:Name="tbUserName4" Width="200" Height="50" Margin="5"
    PlaceHolder="请输入用户名" CornerRadius="20" IsEnabled="False"
    Image="Resources/Images/logo.png"/>


    <TextBox Width="200" Height="30" Margin="5"/>
</StackPanel>


        <!--校验错误提示模板-->
        <Setter Property="Validation.ErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <Border CornerRadius="3" BorderBrush="Red" BorderThickness="1">
                        <StackPanel Orientation="Vertical">
                            <AdornedElementPlaceholder x:Name="Adorned"/>
                            
                            <TextBlock Width="{TemplateBinding Width}" Foreground="Red" FontSize="16">  
                                <TextBlock.Text>
                                    <Binding ElementName="Adorned" Path="AdornedElement.(Validation.Errors)[0].ErrorContent"/>
                                </TextBlock.Text>  
                                <TextBlock.Effect>
                                    <DropShadowEffect Opacity="0.6" ShadowDepth="3" Color="Black"/>
                                </TextBlock.Effect>
                            </TextBlock>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>


<think>好的,我现在需要帮助用户了解如何在C#中为TextBox控件设置占位符。根据用户提供的引用,看起来他们可能在使用不同的框架,比如WPF、UWP或者WinForms,所以需要分别考虑这些情况。 首先,用户提到了引用[3]、[4]、[5],这些引用涉及WPF和WinForms的占位符实现。例如,引用[3]中的XAML代码展示了如何通过自定义控件或附加属性添加占位符,而引用[5]则是WinForms中使用C#代码设置占位符的例子。用户的问题集中在C#中如何实现,所以需要覆盖不同框架的方法。 接下来,我需要确定不同框架下的实现方式。在WPF中,通常通过自定义控件或者附加属性来实现占位符功能,这可能涉及到样式和模板的修改,如引用[3]和[4]所示。而WinForms可能需要使用原生的事件处理,比如TextChanged事件来动态显示和隐藏占位符文本,如引用[5]中的例子。UWP则有内置的PlaceholderText属性,如引用[1]中提到的TextBoxDemo1.xaml.cs中的设置,但用户可能没有明确说明他们使用的框架。 然后,我需要整理出清晰的步骤,分别针对不同框架给出示例。例如,在WinForms中,可以通过处理Enter和Leave事件来切换占位符文本的颜色和内容,确保用户输入时占位符消失。在WPF中,可以使用附加属性或者创建自定义控件,结合样式和触发器来实现类似效果。而UWP则更为简单,直接设置PlaceholderText属性即可。 此外,需要注意用户可能在阅读示例代码时遇到问题,所以需要确保代码的准确性和可复制性。比如,WinForms示例需要说明如何添加事件处理程序,WPF示例需要解释如何定义附加属性和样式,UWP则直接展示属性设置。同时,要提醒用户根据自己项目类型选择合适的方法,并注意命名空间和引用的正确性。 最后,生成相关问题,帮助用户进一步了解占位符的高级用法,比如动态切换语言、美化样式或输入验证,这些可以引导用户深入学习和解决问题。需要确保问题覆盖用户可能感兴趣的扩展领域,并参考之前的引用内容,比如引用[5]中的多语言占位符,引用[4]中的验证错误提示模板。</think>在C#中为TextBox设置占位符的实现方式取决于具体使用的技术框架。以下是针对不同框架的解决方案和示例: ### 一、WPF框架实现 #### 1. 通过附加属性实现(推荐) ```xml <TextBox local:PlaceholderHelper.Placeholder="请输入内容" Style="{StaticResource PlaceholderTextBoxStyle}"/> ``` ```csharp public class PlaceholderHelper { public static readonly DependencyProperty PlaceholderProperty = DependencyProperty.RegisterAttached("Placeholder", typeof(string), typeof(PlaceholderHelper)); public static string GetPlaceholder(DependencyObject obj) => (string)obj.GetValue(PlaceholderProperty); public static void SetPlaceholder(DependencyObject obj, string value) => obj.SetValue(PlaceholderProperty, value); } ``` ```xml <Style x:Key="PlaceholderTextBoxStyle" TargetType="TextBox"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid> <Border Background="{TemplateBinding Background}"> <ScrollViewer x:Name="PART_ContentHost"/> </Border> <TextBlock Text="{TemplateBinding local:PlaceholderHelper.Placeholder}" Foreground="Gray" Visibility="Collapsed" Margin="5,0"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="Text" Value=""> <Setter Property="Visibility" Value="Visible" TargetName="placeholderText"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> ``` ### 二、WinForms实现 ```csharp public partial class Form1 : Form { public Form1() { InitializeComponent(); SetPlaceholder(textBox1, "请输入用户名"); } private void SetPlaceholder(TextBox textBox, string placeholder) { textBox.Text = placeholder; textBox.ForeColor = Color.Gray; textBox.Enter += (s, e) => { if (textBox.Text == placeholder) { textBox.Text = ""; textBox.ForeColor = Color.Black; } }; textBox.Leave += (s, e) => { if (string.IsNullOrWhiteSpace(textBox.Text)) { textBox.Text = placeholder; textBox.ForeColor = Color.Gray; } }; } } ``` ### 三、UWP实现(引用[1]) ```csharp // 直接使用内置属性 textBox.PlaceholderText = "请输入密码"; ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneOnce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值