文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于WPF实现用户头像选择器的示例代码

2024-04-02 19:55

关注

实现思路

制作一个用户头像选择器仿 WeGame

制作一个用户头像选择Canvas为父控件所实现,展示图片使用ImagePath当作上方的蒙版;

Canvas:主要用途方便移动Image,设置ClipToBounds="True"裁剪为一个正方形200x200做为主要展示区域;

Image:展示需要裁剪的图片;

Path:CombinedGeometry[1]绘制蒙版大小200x200效果如下;

当选择一个本地图片的时候判断宽与高谁更大,谁小就将它更改为200 ,另一边做等比缩放后给到DrawingVisual绘制一个新的BitmapFrame[2]给Image控件做展示;

当移动图片的时候右侧展示当前区域使用CroppedBitmap[3]进行裁剪并显示;

源码Github[4] Gitee[5]

核心代码

1)CropAvatar.xaml 代码如下;

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:controls="clr-namespace:WPFDevelopers.Controls">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Basic/ControlBasic.xaml"/>
    </ResourceDictionary.MergedDictionaries>

    <Style TargetType="controls:CropAvatar" BasedOn="{StaticResource ControlBasicStyle}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type controls:CropAvatar}">
                    <Canvas x:Name="PART_Canvas" ClipToBounds="True">
                        <Image x:Name="PART_Image" Cursor="SizeAll" ></Image>
                        <Path x:Name="PART_Layout" 
                              Fill="{DynamicResource BlackSolidColorBrush}" 
                              Width="200" Height="200" 
                              Opacity=".5">
                            <Path.Data>
                                <CombinedGeometry GeometryCombineMode="Xor">
                                    <CombinedGeometry.Geometry1>
                                        <RectangleGeometry Rect="0,0,200,200"/>
                                    </CombinedGeometry.Geometry1>
                                    <CombinedGeometry.Geometry2>
                                        <EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
                                    </CombinedGeometry.Geometry2>
                                </CombinedGeometry>
                            </Path.Data>
                        </Path>
                        <Grid x:Name="PART_Grid" Width="200" Height="200">
                            <Button x:Name="PART_ReplaceButton" Style="{StaticResource PathButton}"
                                    HorizontalAlignment="Right"
                                    VerticalAlignment="Top"
                                    Width="40" Height="40" ToolTip="更换图片"
                                    Visibility="Collapsed">
                                <Button.Content>
                                    <Path Data="{StaticResource PathReplace}"
                                          Fill="{StaticResource PrimaryNormalSolidColorBrush}"
                                          Height="15"
                                          Width="15"
                                          Stretch="Fill" />
                                </Button.Content>
                            </Button>
                            <Button x:Name="PART_AddButton" Style="{StaticResource PathButton}"
                                    Width="40" Height="40" ToolTip="选择图片">
                                <Button.Content>
                                    <Path Data="{StaticResource PathAdd}"
                                          Fill="{StaticResource PrimaryNormalSolidColorBrush}"
                                          Height="20"
                                          Width="20"
                                          Stretch="Fill" 
                                          RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">
                                        <Path.RenderTransform>
                                            <RotateTransform Angle="45"/>
                                        </Path.RenderTransform>
                                    </Path>
                                </Button.Content>
                            </Button>
                        </Grid>
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

2)CropAvatar.cs 代码如下;

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WPFDevelopers.Helpers;

namespace WPFDevelopers.Controls
{
    [TemplatePart(Name = CanvasTemplateName, Type = typeof(Canvas))]
    [TemplatePart(Name = ImageTemplateName, Type = typeof(Image))]
    [TemplatePart(Name = PathTemplateName, Type = typeof(Path))]
    [TemplatePart(Name = GridTemplateName, Type = typeof(Grid))]
    [TemplatePart(Name = ReplaceButtonTemplateName, Type = typeof(Button))]
    [TemplatePart(Name = AddButtonTemplateName, Type = typeof(Button))]
    public partial class CropAvatar : Control
    {
        private const string CanvasTemplateName = "PART_Canvas";
        private const string ImageTemplateName = "PART_Image";
        private const string PathTemplateName = "PART_Layout";
        private const string GridTemplateName = "PART_Grid";
        private const string ReplaceButtonTemplateName = "PART_ReplaceButton";
        private const string AddButtonTemplateName = "PART_AddButton";
        private Point point;
        private const int _size = 200;
        private bool isDown;
        private bool isLeft;
        private CroppedBitmap crop;
        private Canvas canvas;
        private Image image;
        private Path path;
        private Grid grid;
        private Button replaceButton, addButton;
        private int initialX, initialY, voffsetX, voffsetY;
        private double vNewStartX, vNewStartY, _StartX, _StartY, centerX, centerY;
        private BitmapFrame bitmapFrame;

        public ImageSource OutImageSource
        {
            get { return (ImageSource)GetValue(OutImageSourceProperty); }
            set { SetValue(OutImageSourceProperty, value); }
        }

        public static readonly DependencyProperty OutImageSourceProperty =
            DependencyProperty.Register("OutImageSource", typeof(ImageSource), typeof(CropAvatar), new PropertyMetadata(null));


        static CropAvatar()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CropAvatar), new FrameworkPropertyMetadata(typeof(CropAvatar)));
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            canvas = GetTemplateChild(CanvasTemplateName) as Canvas;
            canvas.Loaded += Canvas_Loaded;
            grid = GetTemplateChild(GridTemplateName) as Grid;
            image = GetTemplateChild(ImageTemplateName) as Image;
            image.MouseDown += Image_MouseDown;
            image.MouseMove += Image_MouseMove;
            image.MouseUp += Image_MouseUp;
            image.MouseLeave += Image_MouseLeave;
            path = GetTemplateChild(PathTemplateName) as Path;
            replaceButton = GetTemplateChild(ReplaceButtonTemplateName) as Button;
            replaceButton.Click += ReplaceButton_Click;
            addButton = GetTemplateChild(AddButtonTemplateName) as Button;
            addButton.Click += AddButton_Click;
        }

        private void Canvas_Loaded(object sender, RoutedEventArgs e)
        {
            if (sender is Canvas canvas)
            {
                var width = canvas.ActualWidth;
                var height = canvas.ActualHeight;
                centerX = (width - path.Width) / 2.0d;
                centerY = (height - path.Height) / 2.0d;
                canvas.Clip = new RectangleGeometry(new Rect(centerX, centerY, 200, 200)); 
                Canvas.SetLeft(path, centerX);
                Canvas.SetTop(path, centerY);
                Canvas.SetLeft(grid, centerX);
                Canvas.SetTop(grid, centerY);
            }
        }

        private void Image_MouseLeave(object sender, MouseEventArgs e)
        {
            isDown = false;
            if (isLeft)
                _StartX = Canvas.GetLeft(image);
            else
                _StartY = Canvas.GetTop(image);
        }

        private void Image_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (isDown)
            {
                var vPoint = e.GetPosition(this);
                if (isLeft)
                {
                    _StartX = Canvas.GetLeft(image);
                    initialX = voffsetX;
                }

                else
                {
                    _StartY = Canvas.GetTop(image);
                    initialY = voffsetY;
                }
            }
        }

        private void Image_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && isDown)
            {
                var vPoint = e.GetPosition(this);
                if (isLeft)
                {
                    var voffset = vPoint.X - point.X;
                    vNewStartX = _StartX + voffset;
                    var xPath = Canvas.GetLeft(path);
                    if (vNewStartX <= xPath && vNewStartX >= -(bitmapFrame.Width - 200 - xPath))
                    {
                        Canvas.SetLeft(image, vNewStartX);
                        voffsetX = initialX - (int)voffset;
                        voffsetX = voffsetX < 0 ? 0 : voffsetX;
                        crop = new CroppedBitmap(bitmapFrame, new Int32Rect(voffsetX, 0, _size, _size));

                    }
                }
                else
                {
                    var voffset = vPoint.Y - point.Y;
                    vNewStartY = _StartY + voffset;
                    var yPath = Canvas.GetTop(path);
                    if (vNewStartY <= yPath && vNewStartY >= -(bitmapFrame.Height - 200 - yPath))
                    {
                        Canvas.SetTop(image, vNewStartY);
                        voffsetY = initialY - (int)voffset;
                        voffsetY = voffsetY < 0 ? 0 : voffsetY;
                        crop = new CroppedBitmap(bitmapFrame, new Int32Rect(0, voffsetY, _size, _size));
                    }
                }
                OutImageSource = crop;
            }
        }

        private void Image_MouseDown(object sender, MouseButtonEventArgs e)
        {
            isDown = true;
            point = e.GetPosition(this);
        }

        private void ReplaceButton_Click(object sender, RoutedEventArgs e)
        {
            InitialImage();
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            InitialImage();
        }

        void InitialImage()
        {
            vNewStartX = 0;
            vNewStartY = 0;
            var uri = ControlsHelper.ImageUri();
            if (uri == null) return;
            var bitmap = new BitmapImage(uri);
            if (bitmap.Height > bitmap.Width)
            {
                double scale = (double)bitmap.Width / (double)path.Width;
                image.Width = _size;
                image.Height = (double)bitmap.Height / scale;
                isLeft = false;
            }
            else if (bitmap.Width > bitmap.Height)
            {
                double scale = (double)bitmap.Height / (double)path.Height;
                image.Width = (double)bitmap.Width / scale;
                image.Height = _size;
                isLeft = true;
            }
            bitmapFrame = ControlsHelper.CreateResizedImage(bitmap, (int)image.Width, (int)image.Height, 0);
            image.Source = bitmapFrame;
            if (image.Source != null)
            {
                replaceButton.Visibility = Visibility.Visible;
                addButton.Visibility = Visibility.Collapsed;
            }
            Canvas.SetLeft(grid, centerX);
            Canvas.SetTop(grid, centerY);
            _StartX = (canvas.ActualWidth - image.Width) / 2.0d;
            _StartY = (canvas.ActualHeight - image.Height) / 2.0d;
            Canvas.SetLeft(image, _StartX);
            Canvas.SetTop(image, _StartY);        
            if (isLeft)
            {
                initialX = (int)(image.Width - 200) / 2;
                initialY = 0;
                crop = new CroppedBitmap(bitmapFrame, new Int32Rect(initialX, 0, _size, _size));

            }
            else
            {
                initialY = (int)(image.Height - 200) / 2;
                initialX = 0;
                crop = new CroppedBitmap(bitmapFrame, new Int32Rect(0, initialY, _size, _size));
            }
            OutImageSource = crop;
        }
       
    }
}

3)CropAvatarWindow.xaml使用如下;

<ws:Window x:Class="WPFDevelopers.Samples.ExampleViews.CropAvatarWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
        xmlns:ws="https://github.com/WPFDevelopersOrg.WPFDevelopers.Minimal"
        mc:Ignorable="d"  WindowStyle="ToolWindow" ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen"
        Title="WPF 开发者-头像选择器" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <wpfdev:CropAvatar x:Name="MyCropAvatar"/>
        <Image Grid.Column="1" Name="CropAvatarImage" Source="{Binding ElementName=MyCropAvatar,Path=OutImageSource}" 
               Stretch="Fill" Width="200" Height="200">
            <Image.Clip>
                <EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
            </Image.Clip>
        </Image>
        <UniformGrid Grid.Row="1" Grid.ColumnSpan="2" 
                     HorizontalAlignment="Center" 
                     VerticalAlignment="Center">
            <Button  Content="保存" Click="btnSave_Click" Style="{StaticResource PrimaryButton}" Margin="4,0"/>
            <Button  Content="关闭" Click="btnClose_Click" Margin="4,0"/>
        </UniformGrid>
    </Grid>
</ws:Window>

4) CropAvatarWindow.xaml.cs 代码如下;

using System.Windows;

namespace WPFDevelopers.Samples.ExampleViews
{
    /// <summary>
    /// CropAvatarWindow.xaml 的交互逻辑
    /// </summary>
    public partial class CropAvatarWindow 
    {
        public CropAvatarWindow()
        {
            InitializeComponent();
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
        }
    }
}

5) CropAvatarExample.xaml 使用如下;

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.CropAvatarExample"
             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" 
             xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"
             xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button Content="图像选择器" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click"/>
        <Image Grid.Column="1" Name="MyImage"
               Stretch="Fill" Width="200" Height="200">
            <Image.Clip>
                <EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
            </Image.Clip>
        </Image>
    </Grid>
</UserControl>

6) CropAvatarExample.xaml.cs 代码如下;

using System.Windows.Controls;

namespace WPFDevelopers.Samples.ExampleViews
{
    /// <summary>
    /// CropAvatarExample.xaml 的交互逻辑
    /// </summary>
    public partial class CropAvatarExample : UserControl
    {
        public CropAvatarExample()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var cropAvatarWindow = new CropAvatarWindow();
            if (cropAvatarWindow.ShowDialog() == true)
            {
                MyImage.Source = cropAvatarWindow.CropAvatarImage.Source;
            }
        }
    }
}

参考资料

[1]CombinedGeometry

[2]BitmapFrame

[3]CroppedBitmap

[4]Github

[5]Gitee

到此这篇关于基于WPF实现用户头像选择器的示例代码的文章就介绍到这了,更多相关WPF头像选择器内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯