首页 > 其他分享 >WPF中Image控件的绑定

WPF中Image控件的绑定

时间:2024-03-23 23:11:51浏览次数:24  
标签:控件 BitmapImage string Image 绑定 Bitmap Source WPF

转载自:https://www.cnblogs.com/seekdream/p/5277237.html

背景

  在我们平时的开发中会经常用到Image控件,通过设置Image控件的Source属性,我们可以加载图片,设置Image的source属性时可以使用相对路径也可以使用绝对路径,一般情况下建议使用绝对路径,类似于下面的形式 

1 Source="/Demo;Component/Images/Test.jpg"  

其中Demo表示工程的名称,后面表示具体哪个文件夹下面的哪个图片资源,在程序中,我们甚至可以为Image控件设置 x:Name 属性,在后台代码中动态去改变Image的Source,但我个人认为这种方式不太适合最大量的图片切换,而且增加了View层和代码之间的耦合性,不是和复合MVVM的核心设计思想,所以今天就总结一下Image的动态绑定的形式。

过程

1 常规操作

    要绑定肯定是绑定到Image控件的Source属性上面,我们首先要搞清楚 Source 的类型是什么?

1 public ImageSource Source { getset; }  

  也就是ImageSource类型,当然在我们绑定的时候用的最多的就是BitmapImage这个位图图像啦,我们首先来看看BitmapImage的继承关系:BitmapImage:BitmapSource:ImageSource,最终也是一种ImageSource类型。当然在我们的Model层中我们也可以直接定义一个BitmapImage的属性,然后将这个属性直接绑定到Image的Source上面,当然这篇文章我们定义了一个ImgSource的String类型,所以必须要定义一个转换器Converter,这里分别贴出相应地代码。

  1.1 定义View

1 2 3 4 <Grid Grid.Row="1">       <Image Source="{Binding Path=LTEModel.ImgSource,Converter={StaticResource MyImageConverter}}" Stretch="Fill">       </Image> </Grid>  

  1.2 定义Model

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class LTEModel : BaseModel     {         private string _imageSource = null;         public string ImgSource         {             get             {                 return _imageSource;             }             set             {                 if (value != _imageSource)                 {                     _imageSource = value;                     FirePropertyChanged("ImgSource");                 }             }         }     }  

  1.3 定义转换器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class StringToImageSourceConverter:IValueConverter    {        #region Converter          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)        {            string path = (string)value;            if (!string.IsNullOrEmpty(path))            {                return new BitmapImage(new Uri(path, UriKind.Absolute));            }            else            {                return null;            }        }          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)        {            return null;        }        #endregion    }  

  转换器返回的是Object类型,实际返回的是一个BitmapImage对象。所以我们在写程序绑定的时候一定要弄清绑定的目标和对象之间的关系,这个是非常重要的。

  1.4 定义ViewModel

  下面就是在ViewModel层中来添加绑定,并更新数据源,这里使用的是一个定时器来定时更新数据源:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 public class LTEViewModel : NotifyObject    {        private DispatcherTimer myDispatcher = null;        private Random random = new Random();        public LTEViewModel()        {            GetImageSource();            InitTimer();        }          private LTEModel _lteModel = null;        public LTEModel LTEModel        {            get            {                if (_lteModel == null)                {                    _lteModel = new LTEModel();                }                return _lteModel;            }            set            {                if (value != _lteModel)                {                    _lteModel = value;                    FirePropertyChanged("LTEModel");                }            }        }          private BaseModel _baseModel = null;        public BaseModel BaseModelInstance        {            get            {                if (_baseModel == null)                {                    _baseModel = new BaseModel()                    {                        Title = "分地区LTE分布",                        Time = DateTime.Now.ToString()                    };                }                return _baseModel;            }            set            {                if (value != _baseModel)                {                    _baseModel = value;                    FirePropertyChanged("BaseModelInstance");                }            }        }          private List<string> imgList = new List<string>();        private void GetImageSource()        {            //通过程序集来读取相应的资源的路径            string assemblyLocation = this.GetType().Assembly.Location;            string assLocation = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\"));            string[] img_files = Directory.GetFiles(string.Format("{0}\\Images", assLocation), "*.JPG");            foreach (string img_path in img_files)            {                imgList.Add(img_path);            }        }          private void InitTimer()        {            myDispatcher = new DispatcherTimer();            myDispatcher.Tick += new EventHandler(Timer_Tick);            myDispatcher.Interval = TimeSpan.FromMilliseconds(1000);            myDispatcher.Start();        }          private void Timer_Tick(object sender, EventArgs e)        {            int imageIndex = 0;            if (imgList.Count > 0 && LTEModel != null)            {                imageIndex = random.Next(0, imgList.Count);                LTEModel.ImgSource = imgList[imageIndex];            }            if (_baseModel != null)            {                _baseModel.Time = DateTime.Now.ToString();            }        }    }  

2 扩展应用

  很多时候我们还有一种需求就是已经获取到了.bmp文件,那么我们该如何将该文件绑定到Image上面呢? 通过上面的分析我们大体可以将整个过程分为以下几个部分:1 获取本地文件并加载Bitmap。2 将Bitmap对象转换为BitmapImage对象。3 将BitmapImage绑定到Image的Source属性上面,下面就每一个过程来进行一个分析。

  2.1 加载本地Bitmap文件

  这个通过下面的一行代码就可以搞定,这里fullPath是本地的目录

1 var bitmapImage = new Bitmap(fullPath, true);  

  2.2 将Bitmap对象转换为BitmapImage对象

  在考虑直接转换之前,我们来思考一种常用的情况,如果我们的代码是UI端和Server端分布在两台不同的电脑上面,我们的bmp图片在服务器上,这是我们需要将获取到的图片发送到客户端,这时肯定不会直接传图片,我们会选择将图片转换成字符串或者byte[]数组的形式,下面的示例表示将Bitmap转换成string,并在客户端再次将string转换成Bitmap的方式,看下面的代码。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public static class BitMapToBase64Helper     {         /**        * 将bitmap转换成base64字符串               * @param bitmap        * @return base64 字符串        */         public static string BitmapToString(Bitmap bitmap)         {             using (var memoryStream = new MemoryStream())             {                 bitmap.Save(memoryStream, ImageFormat.Jpeg);                 byte[] byteImage = memoryStream.ToArray();                 // Get Base64                 return Convert.ToBase64String(byteImage);             }         }           /**        * 将base64转换成bitmap图片               * @param string base64字符串        * @return bitmap       */         public static Bitmap StringToBitmap(string base64String)         {             Bitmap bmpReturn = null;             //Convert Base64 string to byte[]             byte[] byteBuffer = Convert.FromBase64String(base64String);             using (var memoryStream = new MemoryStream(byteBuffer))             {                 memoryStream.Position = 0;                 bmpReturn = (Bitmap)Bitmap.FromStream(memoryStream);                 return bmpReturn;             }         }     }  

  有了这个我们就可以实现图片和字符串之间的相互转换了,在获取到Bitmap对象后我们需要通过下面的代码来将Bitmap转换成BitmapImage从而可以将其绑定到Image的Source属性上面。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private BitmapImage BitmapToImageSource(Bitmap bitmap)        {            using (var memory = new MemoryStream())            {                //这里需要将原来的bitmap重新复制一份出来使用newBitmap进行Save 否则会报GDI+中出现一般性错误                //https://stackoverflow.com/questions/15862810/a-generic-error-occurred-in-gdi-in-bitmap-save-method                Bitmap newBitmap = new Bitmap(bitmap);                bitmap.Dispose();                bitmap = null;                  newBitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp);                memory.Position = 0;                BitmapImage bitmapImage = new BitmapImage();                bitmapImage.BeginInit();                bitmapImage.StreamSource = memory;                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;                bitmapImage.EndInit();                  return bitmapImage;            }        }  

  这里需要关注一点就是代码中加了中文注释的那个部分,就是通过string创建出来的Bitmap再将其转换为BitmapImage的时候需要重新创建一个原来Bitmap对象的一个副本,否则会出现 出现GDI+出现一般的错误的Exception,具体的解释可以参考文中的链接。

  2.3 将BitmapImage绑定到Image的Source属性

  这个就不再赘述了,直接将上面步骤中的BitmapImage绑定到Image的Source属性即可。

3 其它应用

  这里说一个通过定义DeviceType属性,然后在Trigger中绑定不同图片的方式,我们来看看这个实现的过程。 

      其实在我们的很多时候,我们并不知道我们需要绑定什么图片,或者说根据数据类型来绑定图片,这个在定义数据模板的时候经常使用到,下面就介绍一下,根据类型来绑定相应的图片,然后通过定义 

1 2 3 4 5 6 7 public enum DeviceType {     SheXiangJi,   KaKou,   DianZiJingCha,   MingJin }  

  这种类型,通过不同的类型来绑定到不同的图片,这个也是一个非常重要的应用,我们一定要注意使用的方法,这里只是简单介绍一下。     

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <ItemsControl ItemsSource="{Binding DeviceList,RelativeSource={RelativeSource TemplatedParent}}" Grid.Row="2">                            <ItemsControl.Template>                                <ControlTemplate TargetType="ItemsControl">                                    <UniformGrid Columns="3" Rows="7" IsItemsHost="True"></UniformGrid>                                </ControlTemplate>                            </ItemsControl.Template>                            <ItemsControl.ItemTemplate>                                <DataTemplate>                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="20 0 0 0" VerticalAlignment="Center" SnapsToDevicePixels="True">                                        <Image  x:Name="icon1" Width="48" Height="48" RenderOptions.BitmapScalingMode="NearestNeighbor" VerticalAlignment="Center"></Image>                                        <TextBlock Margin="10 0 0 0" Foreground="#fff" ToolTip="{Binding Name}" FontSize="40" Text="{Binding Name}" HorizontalAlignment="Left" VerticalAlignment="Center"></TextBlock>                                    </StackPanel>                                    <DataTemplate.Triggers>                                        <DataTrigger Binding="{Binding Type}" Value="SheXiangJi">                                            <Setter Property="Source" Value="/IGisControls.JTJ.UIControls;component/images/camera.png" TargetName="icon1"></Setter>                                        </DataTrigger>                                        <DataTrigger Binding="{Binding Type}" Value="KaKou">                                            <Setter Property="Source" Value="/IGisControls.JTJ.UIControls;component/images/Bayonet.png" TargetName="icon1"></Setter>                                        </DataTrigger>                                        <DataTrigger Binding="{Binding Type}" Value="DianZiJingCha">                                            <Setter Property="Source" Value="/IGisControls.JTJ.UIControls;component/images/epolice.png" TargetName="icon1"></Setter>                                        </DataTrigger>                                        <DataTrigger Binding="{Binding Type}" Value="MingJin">                                            <Setter Property="Source" Value="/IGisControls.JTJ.UIControls;component/images/Police_A.png" TargetName="icon1"></Setter>                                        </DataTrigger>                                    </DataTemplate.Triggers>                                </DataTemplate>                            </ItemsControl.ItemTemplate>                        </ItemsControl>  

    另外和Image很类似的就是ImageBrush控件的使用,具体的使用方法如下代码所示。 

1 <ImageBrush ImageSource="/IGisControls.JTJ.UIControls;component/images/screenBG.jpg" Stretch="Fill"></ImageBrush>  

  用法也差不多,同样可以通过绑定的方式来添加图片,不过在使用的时候还是需要注意一下就是设置当前图片的生成操作为Resource。

标签:控件,BitmapImage,string,Image,绑定,Bitmap,Source,WPF
From: https://www.cnblogs.com/jyj666/p/18091873

相关文章

  • WPF initialization for opening and unitialization for closing process
    //xaml<Windowx:Class="WpfApp10.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mic......
  • c# 调用ImageMagick实现HEIC格式的图片转成jpg
    nuget安装Magick.NET-Q8-AnyCPU我项目Framework未4.5.1这安装的7.17.0版本的包:程序集引用:usingImageMagick;ConvertHeicToJpg方法转换代码如下:点击查看代码///<summary>///Heic转ToJpg///</summary>///<paramname="heicPath......
  • 鸿蒙自定义控件实现罗盘数字时钟效果
    前言:DevEcoStudio版本:4.0.0.600关注过我的小伙伴一定知道我之前写过一篇基于Android的 仿抖音效果的数字时钟罗盘 最近看了鸿蒙的Canvas组件,今天通过Canvas组件也实现下罗盘数字时钟的效果。参考链接:OpenHarmonyCanvas  OpenHarmonyCanvasrenderingcontext2d效果:......
  • Imagen: Photorealistic Text-to-Image Diffusion Models with Deep Language Underst
    名称Imagen:PhotorealisticText-to-ImageDiffusionModelswithDeepLanguageUnderstanding时间:22/05机构:GoogleTL;DR发现使用LLM(T5)可以作为text2image任务的textencoder,并且提升LLM模型size相对于提升imageDM模型size性价比更高,生成的图像保真度更高,内容也更符合文......
  • 动态控件之UI和数据加载分离
    一、问题说明比如一个弹框页面中包含listbox控件,弹框页面打开时,先进行listbox初始化,然后再进行数据加载,如果数据加载较慢,这里就会出现,弹框一直无法显示出来,直到数据加载完成,赋值给listbox控件,才会显示。_listbox.ItemsSource=data; 二、解决方式解决方式也简单,就是异步,......
  • 动态控件之控件的数据绑定
    一、示例需求说明以进度条ProgressBar控件为例,C#动态生成ProgressBar实例_progressBar,并指定_progressBar.IsVisible=IsBusy,当iIsBusy发生变化时,需要产生相应的效果。 二、方式一定义属性:bool_isBusy=false;publicboolIsBusy{get=>_isBusy;set{......
  • C# 02 控件
    1.焦点状态ActiveControl和FocusActiveControl=textBox1;默认光标焦点在文本框textBox1处textBox1.Focus();焦点转移到textBox12.日期选择显示在文本框创建伪DateTimePicker:TextBox文本框并上DateTimePicker缩小至箭头版。privatevoiddateTimePicker1_Cl......
  • [Container] Building and Running Container Images
    Stepstocreateandruncontainers:1.CreateaDockerfile2.UsetheDockerfiletocreateacontainerimage3.UsethecontainerimagetocreatearunningcontainerDockerfileexampleFROMalpine#DefinesthebaseimageCMD["echo","Hel......
  • [转]WPF 使用 Dispatcher 的 InvokeAsync 和 BeginInvoke 的异常处理差别
    一般认为WPF的Dispatcher的InvokeAsync方法是BeginInvoke方法的平替方法和升级版,接近在任何情况下都应该在业务层使用InvokeAsync方法代替BeginInvoke方法。然而在异常的处理上,这两个方法还是有细微的差别的,不能说是坏事,依然可以认为使用InvokeAsync方法代替BeginI......
  • 动态控件之ItemsPanelTemplate
    一、Axaml生成列表框有一个属性,其中包含一个用于布局列表项的模板控件。默认情况下,这是一个堆叠面板。为了使专辑封面填充所有空间,可以将面板模板更改为包装面板。方式如下:<ListBoxItemsSource="{BindingSearchResults}"SelectedItem="{BindingSelectedAlbum}"Backgro......