WPF 自定义图片剪切器 - 头像剪切。你懂得

说废话,无卵用、代码可能有点乱


一、剪切器界面设计

<UserControl x:Class="DialogEx.Controls.ImageDealer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" Background="Transparent"
             SnapsToDevicePixels="True" 
             PreviewMouseDown="UserControl_MouseDown" PreviewMouseUp="UserControl_MouseUp" MouseLeave="UserControl_MouseLeave" PreviewMouseMove="UserControl_MouseMove"
             >
    <Grid Name="MainGrid" MinHeight="200" MinWidth="200" >
            <Image Name="SoureceImage" Stretch="Fill"></Image>
            <Border Name="ImageArea"  BorderBrush="Red" BorderThickness="1,1,1,1" Panel.ZIndex="5" Margin="50"  Width="100" Height="100"> 
            <Grid >
                <Rectangle Name="R_LeftUp"    Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
                <Rectangle Name="R_Up"        Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
                <Rectangle Name="R_RightUp"   Width="5" Height="5" Margin="-3" VerticalAlignment="Top"    HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
                <Rectangle Name="R_Right"     Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
                <Rectangle Name="R_RightDown" Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Right"  Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
                <Rectangle Name="R_Down"      Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
                <Rectangle Name="R_LeftDown"  Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
                <Rectangle Name="R_Left"      Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Left"   Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
                <!--<GridSplitter Height="5" Width="5" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"></GridSplitter>-->
            </Grid>
        </Border>

    </Grid>
</UserControl>


二、剪辑器后台设计

using DialogEx.Class;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DialogEx.Controls
{
     
    public partial class ImageDealer : UserControl
    {
        #region 公共字段

        public static readonly RoutedEvent OnCutImagingEventHandler = EventManager.RegisterRoutedEvent("OnCutImaging", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ImageDealer));
        public event RoutedEventHandler OnCutImaging
        {
            add { base.AddHandler(OnCutImagingEventHandler, value); }
            remove { base.RemoveHandler(OnCutImagingEventHandler, value); }
        }
        private BitmapImage _BitSource;
        public BitmapImage BitSource
        {
            get { return this._BitSource; }
            set 
            {
                this._BitSource = value;
                this.SoureceImage.Source = value;
                //CutImage();
            } 
        }
        #endregion

        #region 依赖属性

        /// <summary>
        /// 边距
        /// </summary>
        public double MaxMargin = 2;

        //public Brush BorderBrush;
        
        #endregion

        #region ==私有字段==
        /// <summary>
        /// 鼠标样式
        /// </summary>
        private Cursor MouseCursor = Cursors.Arrow;
        /// <summary>
        /// 鼠标位置
        /// </summary>
        private MouseLocationEnum MouseLocation = MouseLocationEnum.None;
        /// <summary>
        /// 鼠标行为
        /// </summary>
        private MouseActionEx Action { get; set; }
        /// <summary>
        /// 边框粗细
        /// </summary>
        private double BorderWidth = 1;
        /// <summary>
        /// 拖拽前鼠标按下位置
        /// </summary>
        private Point MouseDownPoint;
        /// <summary>
        /// 拖拽前控件位置
        /// </summary>
        private Point MouseDownLocate;
        #endregion

        #region ==方法==
        public ImageDealer()
        {
            InitializeComponent();
        }
        /// <summary>
        /// 计算区域圆点及宽高
        /// </summary>
        /// <param name="MouseButtonLocate">鼠标相对背景MainGrid位置</param>
        /// <param name="IsRectangle">是否正方形</param>
        /// <returns>NULL 或 具体值</returns>
        private RectangleAreaModel CalculatedArea(Point MouseButtonLocate, bool IsRectangle)
        {
            Point Locate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
            //边框宽度
            double BorderWidth = this.BorderWidth;
            //整体宽度
            double RectWidth = this.ImageArea.ActualWidth;
            //整体高度
            double RectHeight = this.ImageArea.ActualHeight;

            //裁剪区域
            Point OriginalPoint = new Point(0, 0);//圆点坐标
            Point TheoryPoint = new Point(0, 0);  //理论坐标
            double TheoryWidth = 0;   //理论宽度
            double TheoryHeight = 0;  //理论高度
            switch (MouseLocation)
            {
                case MouseLocationEnum.Left:
                    {
                        this.Cursor = Cursors.SizeWE;

                        OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + RectHeight / 2);//右中部位置
                        TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : RectHeight;

                        TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y - TheoryHeight / 2);
                    }
                    break;
                case MouseLocationEnum.LeftUp:
                    {
                        this.Cursor = Cursors.SizeNWSE;

                        OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//右下部位置
                        TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;

                        TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
                    }
                    break;
                case MouseLocationEnum.Up:
                    {
                        this.Cursor = Cursors.SizeNS;

                        OriginalPoint = new Point(Locate.X + RectWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//下中部位置
                        TheoryHeight = OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;
                        TheoryWidth = IsRectangle == true ? TheoryHeight : RectWidth;

                        TheoryPoint = new Point(OriginalPoint.X - TheoryWidth / 2, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
                    }
                    break;
                case MouseLocationEnum.RightUp:
                    {
                        this.Cursor = Cursors.SizeNESW;

                        OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//左下部位置
                        TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;

                        TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
                    }
                    break;
                case MouseLocationEnum.Right:
                    {
                        this.Cursor = Cursors.SizeWE;

                        OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + RectHeight / 2);//左中部位置
                        TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : RectHeight;

                        TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y - TheoryHeight / 2);
                    }
                    break;
                case MouseLocationEnum.RightDown:
                    {
                        this.Cursor = Cursors.SizeNWSE;

                        OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + BorderWidth / 2);//左上部位置
                        TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;

                        TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y - BorderWidth / 2);
                    }
                    break;
                case MouseLocationEnum.Down:
                    {
                        this.Cursor = Cursors.SizeNS;

                        OriginalPoint = new Point(Locate.X + RectWidth / 2, Locate.Y + BorderWidth / 2);//上中部位置
                        TheoryHeight = MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;
                        TheoryWidth = IsRectangle == true ? TheoryHeight : RectWidth;

                        TheoryPoint = new Point(OriginalPoint.X - TheoryWidth / 2, OriginalPoint.Y - BorderWidth / 2);
                    }
                    break;
                case MouseLocationEnum.LeftDown:
                    {
                        this.Cursor = Cursors.SizeNESW;

                        OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + BorderWidth / 2);//右上部位置
                        TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
                        TheoryHeight = IsRectangle == true ? TheoryWidth : OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;

                        TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y - BorderWidth / 2);
                    }
                    break;
                default:
                    return null;
            }
            return new RectangleAreaModel()
            {
                X = TheoryPoint.X,
                Y = TheoryPoint.Y,
                Width = TheoryWidth,
                Height = TheoryHeight
            };
        }
        /// <summary>
        /// 图片剪切
        /// </summary>
        public void CutImage()
        {
            if (this.BitSource != null)
            {
                BitmapSource source = (BitmapSource)this.BitSource;
                //计算比例
                Point Locate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
                int dWidth = (int)((this.ImageArea.ActualWidth * 1.0 / this.MainGrid.ActualWidth) * source.PixelWidth);
                int dHeight = (int)((this.ImageArea.ActualHeight * 1.0 / this.MainGrid.ActualHeight) * source.PixelHeight);
                int dLeft = (int)((Locate.X * 1.0 / this.MainGrid.ActualWidth) * source.PixelWidth);
                int dTop = (int)((Locate.Y * 1.0 / this.MainGrid.ActualHeight) * source.PixelHeight);
                //像素区域
                Int32Rect cutRect = new Int32Rect(dLeft, dTop, dWidth, dHeight);
                //数组字节数
                int stride = source.Format.BitsPerPixel * cutRect.Width / 8;
                byte[] data = new byte[cutRect.Height * stride];
                source.CopyPixels(cutRect, data, stride, 0);
                //创建
                BitmapSource bit = BitmapSource.Create(dWidth, dHeight, 0, 0, PixelFormats.Bgr32, null, data, stride);
                //通知订阅
                RaiseEvent(new RoutedEventArgs(OnCutImagingEventHandler, bit));
            }
        }
        /// <summary>
        /// 视图转图片
        /// </summary>
        /// <param name="vsual"></param>
        /// <param name="nLeft"></param>
        /// <param name="nTop"></param>
        /// <param name="nWidth"></param>
        /// <param name="nHeight"></param>
        /// <returns></returns>
        private RenderTargetBitmap RenderVisaulToBitmap(Visual vsual,int nLeft, int nTop,int nWidth, int nHeight)
        {
            var rtb = new RenderTargetBitmap(nWidth, nHeight, nLeft, nTop, PixelFormats.Default);
            rtb.Render(vsual);

            return rtb;
        }
        /// <summary>
        /// Bitmap转图片
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public BitmapSource ToBitmapSource(System.Drawing.Bitmap bmp)
        {
            BitmapSource returnSource;

            try
            {
                returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            }
            catch
            {
                returnSource = null;
            }

            return returnSource;

        }
        #endregion
       
        #region ==事件==
        
        //按下鼠标
        private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
        {
            this.MouseLocation = Class.MouseLocationEnum.None;
            if (e.OriginalSource.GetType() == typeof(Rectangle))
            {
                Rectangle Act = e.OriginalSource as Rectangle;
                switch (Act.Name)
                {
                    case "R_Left": MouseLocation = Class.MouseLocationEnum.Left; break;
                    case "R_LeftUp": MouseLocation = Class.MouseLocationEnum.LeftUp; break;
                    case "R_Up": MouseLocation = Class.MouseLocationEnum.Up; break;
                    case "R_RightUp": MouseLocation = Class.MouseLocationEnum.RightUp; break;
                    case "R_Right": MouseLocation = Class.MouseLocationEnum.Right; break;
                    case "R_RightDown": MouseLocation = Class.MouseLocationEnum.RightDown; break;
                    case "R_Down": MouseLocation = Class.MouseLocationEnum.Down; break;
                    case "R_LeftDown": MouseLocation = Class.MouseLocationEnum.LeftDown; break;
                    default: MouseLocation = Class.MouseLocationEnum.None; break;
                }

                this.Action = MouseActionEx.Drag;
            }
            else
            {
                this.MouseDownPoint = Mouse.GetPosition(e.Source as FrameworkElement);//WPF方法
                this.MouseDownLocate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
                if ((this.MouseDownLocate.X < this.MouseDownPoint.X && this.MouseDownPoint.X < this.MouseDownLocate.X + this.ImageArea.ActualWidth) &&
                    (this.MouseDownLocate.Y < this.MouseDownPoint.Y && this.MouseDownPoint.Y < this.MouseDownLocate.Y + this.ImageArea.ActualHeight)
                    )
                {
                    this.Action = MouseActionEx.DragMove;
                }
            }

        }
        //弹起鼠标
        private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
        {
            this.Action = MouseActionEx.None;
            this.Cursor = Cursors.Arrow;
        }
        //移动鼠标
        private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            //鼠标相对空间区域位置
            Point MousePoint = e.GetPosition((IInputElement)this.MainGrid);
            Point ImageLocate= this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
            if (ImageLocate.X <= MousePoint.X && MousePoint.X <= ImageLocate.X + this.ImageArea.ActualWidth &&
                ImageLocate.Y <= MousePoint.Y && MousePoint.Y <= ImageLocate.Y + this.ImageArea.ActualHeight)
            {
                this.Cursor = Cursors.Hand;
            }
            else
            {
                this.Cursor = Cursors.Arrow;
            }
            //边框拉伸
            if (this.Action == MouseActionEx.Drag)
            {
                this.Cursor = this.MouseCursor;
                //剪辑图片区域宽高
                double ImageAreaWidth = this.ImageArea.ActualWidth;
                double ImageAreaHeight = this.ImageArea.ActualHeight;

                //裁剪区域理论位置
                RectangleAreaModel Model = this.CalculatedArea(MousePoint, true);
                if (Model != null)
                {
                    //不能超出边界区域
                    if (Model.X + Model.Width + MaxMargin > this.ActualWidth ||
                        Model.Y + Model.Height + MaxMargin > this.ActualHeight ||
                        Model.X < MaxMargin ||
                        Model.Y < MaxMargin
                        )
                    {
                        this.Cursor = Cursors.Arrow;
                        this.Action = MouseActionEx.None;
                        return;
                    }
                    this.ImageArea.Width = Model.Width;
                    this.ImageArea.Height = Model.Height;

                    this.ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
                    this.ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top);
                    this.ImageArea.SetValue(MarginProperty, new Thickness(Model.X, Model.Y, 0, 0));

                    CutImage();
                }
            }
            else if (this.Action == MouseActionEx.DragMove)//拖动
            {
                double Left = this.MouseDownLocate.X + (MousePoint.X - MouseDownPoint.X);
                double Top = this.MouseDownLocate.Y + (MousePoint.Y - MouseDownPoint.Y);
                //不能超出边界区域
                if (Left < MaxMargin ||
                    Top < MaxMargin ||
                    (Left + this.ImageArea.ActualWidth + MaxMargin) > this.ActualWidth ||
                    (Top + this.ImageArea.ActualHeight + MaxMargin) > this.ActualHeight)
                {
                    this.Cursor = Cursors.Arrow;
                    this.Action = MouseActionEx.None;
                    return;
                }
                this.ImageArea.Width = this.ImageArea.ActualWidth;
                this.ImageArea.Height = this.ImageArea.ActualHeight;

                this.ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
                this.ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top);
                this.ImageArea.SetValue(MarginProperty, new Thickness(Left, Top, 0, 0));

                CutImage();
            }
            else
            {
                //this.Cursor = Cursors.Arrow;
            }
        }
        //鼠标离开
        private void UserControl_MouseLeave(object sender, MouseEventArgs e)
        {
            this.Action = MouseActionEx.None;

        }
        #endregion

        
    }
}


三、还需要一个蛋疼的辅助类


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DialogEx.Class
{
    /// <summary>
    /// 鼠标八大位置枚举
    /// </summary>
    public enum MouseLocationEnum
    {
        None,
        Left,
        Up,
        Right,
        Down,
        LeftUp,
        LeftDown,
        RightUp,
        RightDown
    }
    /// <summary>
    /// 
    /// </summary>
    public class RectangleAreaModel
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
    }
    /// <summary>
    /// 鼠标状态
    /// </summary>
    public enum MouseActionEx
    {
        /// <summary>
        /// 无
        /// </summary>
        None,
        /// <summary>
        /// 拖拽
        /// </summary>
        Drag,
        /// <summary>
        /// 拖动
        /// </summary>
        DragMove
    }

    public enum SculptureAction
    {
        Nomal,
        Video,
        Image,
    }

}


四、使用方法 - 下面这个是框架下的事件请尝试改成普通事件。我比较懒 - 希望能看懂。

<pre name="code" class="csharp">界面使用
</pre><pre name="code" class="csharp">xmlns:MyControls="clr-namespace:DialogEx.Controls;assembly=DialogEx"
<MyControls:ImageDealer Panel.ZIndex="0" x:Name="ImageDealer" cal:Message.Attach="[Event OnCutImaging]=[Action OnCutImaging($EventArgs)]"></MyControls:ImageDealer>
 
/// <summary>  
/// 截图中 - 实时
<span style="white-space:pre">	</span>/// </summary>
        /// <param name="source"></param>
        public void OnCutImaging(object source)
        {
            if (source != null && source.GetType() == typeof(RoutedEventArgs))
            {
                // if (((RoutedEventArgs)source).OriginalSource.GetType() == typeof(CroppedBitmap))
                {
<pre name="code" class="csharp"><span style="white-space:pre">			</span>//得到了截图图片
                    BitmapSource CurBitMap = (BitmapSource)((RoutedEventArgs)source).OriginalSource;
                    
                    //下面就是对接到的图片处理了。建议将图片保存在Image控件<span style="font-family: Arial, Helvetica, sans-serif;">中。界面上用ContentPresenter。
<span style="white-space:pre">		</span>}
            }
        }
 
 

五、关于明明截图成功,更换了头像。结果界面上显示的头像仍是以前的头像。

那么你肯能碰到这个问题了

http://blog.csdn.net/lvguoshan/article/details/47172109



六、最近刚根据本篇缺陷写了个升级版。由于篇幅问题重新写了一篇新的

http://blog.csdn.net/lvguoshan/article/details/48627031




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: WPF是一种强大的UI框架,它提供了许多控件,其中包括时间选择控件。但是,由于在特定的应用程序中,需要自定义时间选择以满足一些个性化需求。在这种情况下,可以使用WPF自定义控件来创建自己的时间选择控件。 首先,在WPF中创建时间选择控件,需要使用Calendar控件和TimePicker控件。Calendar控件用于显示日期,而TimePicker控件用于选择时间。时间选择控件的主体是StackPanel控件。在StackPanel控件中添加了两个控件Calendar和TimePicker,以实现时间选择的基本功能。 然后,需要在时间选择控件中定义一些附加属性,例如:选定日期、选定时间等等,以实现一些高级功能。 最后,为时间选择控件添加样式,并实现一些触发和动画效果,以使其外观和功能与应用程序的主题相匹配。 实现WPF自定义时间选择可能需要一些时间和经验,但对于需要一个不寻常的时间选择的应用程序来说,是值得的。 这样的时间选择是用户友好的,具有很好的设计和功能,并且以C#编写,可以很容易地与WPF应用程序集成。 ### 回答2: WPF自定义时间选择是一种功能强大、灵活性高的工具,它可以根据需求自行设计不同的选择,可以实现小时、分钟、秒数的选择等多种功能。 首先,我们需要使用WPF自带的DatePicker控件和TimePicker控件来实现时间选择。接下来,我们可以自定义控件的样式和模板,使其更符合我们的设计需求。 在自定义控件的样式时,我们需要设置控件的各个属性,比如控件的边框、背景、字体等。同时,我们可以通过设置样式来调整控件的布局和显示效果。 在时间选择的实现中,需要涉及到一些比较复杂的计算,比如计算时间的差值、时间的格式转换等。我们可以使用C#中的DateTime类和TimeSpan类来实现这些功能。 最后对于自定义时间选择的控件事件,需要自定义一些控件事件,使其更加符合我们的设计需求。比如增加或减少系统时钟里的时间。 总而言之,实现WPF自定义时间选择需要对WPF控件、样式、模板、计算和控件事件等各个方面有深入的了解。只有掌握了这些知识,才能够设计出优秀的时间选择,满足用户的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值