文件墙 CFilewall 记于 2013-09-26 == @[代码] [C#] []WPF] #### 使用了一些公司的组件和放大,但是不多,可以单独抽取出来 --- 程序结构 - Control - CS - FileWallItemsControl.cs - XAML - FileElementUserControl.xaml - Images - Model - FileModel.cs - FileModelContainer.cs - Themes - Tools - ConstantClass.cs - App.xaml - FileContainers - FileWallUserControl.xaml - LoadingUserControl.xaml - MainWindow.xaml --- ## App.xaml ## > 程序启动文件 ### App.xaml ### 引入资源程序集 ```css ``` ### App.xaml.cs ### ValidatInstance 设置程序为单例 定义整个应用程序需要用到的变量 ```css namespace CFileWall { /// /// App.xaml 的交互逻辑 /// public partial class App : Application { Mutex mutex; public static FileInfo[] Files { get; set; } public static CFileWall.Model.FileModel[] FileModels { get; set; } protected override void OnStartup(StartupEventArgs e) { ValidatInstance(); Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; base.OnStartup(e); } void ValidatInstance() { bool creatednew = false; mutex = new Mutex(false, "CFileWall", out creatednew); if (!creatednew) { //Application.Current.Shutdown(); App.Current.Shutdown(); return; } } void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = true; } } } ``` ## FileWallUserControl.xaml ## ### FileWallUserControl.xaml ### ```css <FileWall_Control_XAML:FileElementUserControl Width="{Binding Width}" Height="{Binding Height}" Source="{Binding Source}" Type="{Binding Type}"> <Sinnel_Mvvm_Command:InvokeCommandAction Command="{Binding Loaded}" CommandName="Loaded" /> <Micro_Control:SurfaceScrollViewer x:Name="surfaceScrollView" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" Opacity="{Binding ItemsControlOpacity}" PreviewMouseDown="surfaceScrollView_PreviewMouseDown" PreviewMouseUp="surfaceScrollView_PreviewMouseUp" PreviewTouchDown="surfaceScrollView_PreviewTouchDown" PreviewTouchUp="surfaceScrollView_PreviewTouchUp"> <FileWall_Control_CS:FileWallItemsControl x:Name="itemsControl_Displayer" HorizontalAlignment="Left" ItemTemplate="{DynamicResource DataTemplate}" ItemsPanel="{DynamicResource ItemsPanelTemplate}" > <Micro_Control:ScatterView x:Name="surfaceScatterViewer" > ``` ### FileWallUserControl.xaml.cs ### ```css namespace CFileWall { /// /// FileWallUserControl.xaml 的交互逻辑 /// 文件容器 /// public partial class FileWallUserControl : UserControl { private Point m_MouseDownPoint = new Point(); private Point m_OldItemCenter = new Point(); private double m_OldItemWidth = 0D; private double m_OldItemHeight = 0D; #region 依赖项属性 public ObservableCollection FileCollection { get { return (ObservableCollection)GetValue(FileCollectionProperty); } set { SetValue(FileCollectionProperty, value); } } /// /// 依赖属性,文件集合 /// public static readonly DependencyProperty FileCollectionProperty = DependencyProperty.Register("FileCollection", typeof(ObservableCollection), typeof(FileWallUserControl), new UIPropertyMetadata(new ObservableCollection())); /// /// 控件透明度 /// public double ItemsControlOpacity { get { return (double)GetValue(ItemsControlOpacityProperty); } set { SetValue(ItemsControlOpacityProperty, value); } } public static readonly DependencyProperty ItemsControlOpacityProperty = DependencyProperty.Register("ItemsControlOpacity", typeof(double), typeof(FileWallUserControl), new UIPropertyMetadata(1D)); /// /// 水印图片 /// public string WaterMarkImage { get { return (string)GetValue(WaterMarkImageProperty); } set { SetValue(WaterMarkImageProperty, value); } } public static readonly DependencyProperty WaterMarkImageProperty = DependencyProperty.Register("WaterMarkImage", typeof(string), typeof(FileWallUserControl), new UIPropertyMetadata("")); #endregion public FileWallUserControl() { InitializeComponent(); this.DataContext = this; if (App.FileModels != null && App.FileModels.Length > 0) { foreach (var item in App.FileModels) { string extension = new System.IO.FileInfo(item.FullName).Extension; if (extension.Equals(".ini")) { continue; } FileModelContainer container = new FileModelContainer(item); FileCollection.Add(container); } itemsControl_Displayer.ItemsSource = FileCollection; Loaded += delegate { //string watermarkUri; //Touco.Shinning.Core.ToolClass.WaterMarkOperations.SetWaterMark(out watermarkUri); //WaterMarkImage = watermarkUri; }; } } /// /// 鼠标按下 /// /// /// private void surfaceScrollView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { m_MouseDownPoint = e.GetPosition(this); } /// /// 鼠标松开 /// /// /// private void surfaceScrollView_PreviewMouseUp(object sender, MouseButtonEventArgs e) { Point mouseUpPoint = e.GetPosition(this); if (Math.Abs(mouseUpPoint.X - m_MouseDownPoint.X) < 10 && Math.Abs(mouseUpPoint.Y - m_MouseDownPoint.Y) < 10) { VisualTreeHelper.HitTest(sender as Visual, null, new HitTestResultCallback((result) => { if(result.VisualHit.GetType() != typeof(Control.XAML.FileElementUserControl)) { return HitTestResultBehavior.Continue; } if(surfaceScatterViewer.Items.Count==0) { DisplayItem((result.VisualHit as Control.XAML.FileElementUserControl).DataContext as Model.FileModelContainer); } return HitTestResultBehavior.Stop; }), new PointHitTestParameters(e.GetPosition(this))); } } /// /// 手指按下 /// /// /// private void surfaceScrollView_PreviewTouchDown(object sender, TouchEventArgs e) { m_MouseDownPoint = e.GetTouchPoint(this).Position; } /// /// 手指离开 /// /// /// private void surfaceScrollView_PreviewTouchUp(object sender, TouchEventArgs e) { Point mouseUpPoint = e.GetTouchPoint(this).Position; if (Math.Abs(mouseUpPoint.X - m_MouseDownPoint.X) < 10 && Math.Abs(m_MouseDownPoint.Y - mouseUpPoint.Y) < 10) { VisualTreeHelper.HitTest(sender as Visual, null, new HitTestResultCallback((result) => { if (result.VisualHit.GetType() != typeof(Control.XAML.FileElementUserControl)) { return HitTestResultBehavior.Continue; } if (surfaceScatterViewer.Items.Count == 0) { DisplayItem((result.VisualHit as Control.XAML.FileElementUserControl).DataContext as FileModelContainer); } return HitTestResultBehavior.Stop; }),new PointHitTestParameters(e.GetTouchPoint(this).Position)); } } /// /// 返回图片鼠标单击或手指离开 /// /// /// private void image_Back_PreviewMouseUp(object sender, MouseButtonEventArgs e) { App.Current.MainWindow.Close(); } /// /// 被单独展示的文件的双击事件 /// /// /// void scatterViewItem_DoubleTapped(object sender, RoutedEventArgs e) { image_Back.Visibility = System.Windows.Visibility.Visible; ZoomIn(sender as BaseScatterViewItem); } #region 公共方法 /// /// 放大文件 /// /// void ZoomOut(BaseScatterViewItem scatterViewItem) { double ratio = scatterViewItem.Width / scatterViewItem.Height; double newWidth, newHeight; if (scatterViewItem.Width / scatterViewItem.Height > (this.ActualWidth) / (this.ActualHeight)) { newWidth = this.ActualWidth * 0.75; newHeight = newWidth / ratio; } else { newHeight = this.ActualHeight * 0.75; newWidth = newHeight * ratio; } Point newCenter = new Point(CFileWall.Tools.ConstantClass.SysWidth / 2, CFileWall.Tools.ConstantClass.SysHeight / 2); scatterViewItem.ApplyAnimation(newHeight, newWidth, 0, 1, newCenter, 350, delegate { scatterViewItem.Center = newCenter; scatterViewItem.Opacity = 1; scatterViewItem.Width = newWidth; scatterViewItem.Height = newHeight; scatterViewItem.Orientation = 0; }); DoubleAnimation opacityAnimation = new DoubleAnimation() { To = 0, Duration = TimeSpan.FromMilliseconds(350) }; Storyboard.SetTarget(opacityAnimation, this); Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(FileWallUserControl.ItemsControlOpacityProperty)); Storyboard sb = new Storyboard(); sb.Children.Add(opacityAnimation); sb.Begin(); } /// /// 缩小文件 /// /// void ZoomIn(BaseScatterViewItem scatterViewItem) { scatterViewItem.ApplyAnimation(m_OldItemHeight, m_OldItemWidth, 0, 1, m_OldItemCenter, 350, delegate { if (scatterViewItem is VideoScatterViewItem) (scatterViewItem as VideoScatterViewItem).VideoSource = null; surfaceScatterViewer.Items.Remove(scatterViewItem); }); DoubleAnimation opacityAnimation = new DoubleAnimation() { To = 1, Duration = TimeSpan.FromMilliseconds(350) }; Storyboard.SetTarget(opacityAnimation, this); Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(FileWallUserControl.ItemsControlOpacityProperty)); Storyboard sb = new Storyboard(); sb.Children.Add(opacityAnimation); sb.Begin(); } /// /// 展示文件 /// /// void DisplayItem(FileModelContainer fmc) { BaseScatterViewItem scatterViewItem = BaseScatterViewItem.CreateScatterViewItem(new Touco.Shinning.Core.Model.SurfaceItem() { FileLink = fmc.Source, FileType = "Image" }, false); scatterViewItem.InitialCompleted += delegate { scatterViewItem.Opacity = 1; double dot = scatterViewItem.Width / scatterViewItem.Height; scatterViewItem.Width = fmc.Width; scatterViewItem.Height = fmc.Height; m_OldItemHeight = fmc.Height; m_OldItemWidth = fmc.Width; image_Back.Visibility = System.Windows.Visibility.Hidden; scatterViewItem.CanRotate = true; ZoomOut(scatterViewItem); }; scatterViewItem.IsShowClosed = false; ContentPresenter contentPresenter = itemsControl_Displayer.ItemContainerGenerator.ContainerFromItem(fmc) as ContentPresenter; Point pCenter = contentPresenter.TranslatePoint(new Point(contentPresenter.ActualWidth / 2, contentPresenter.ActualHeight / 2), this); m_OldItemCenter = pCenter; scatterViewItem.Center = pCenter; scatterViewItem.Opacity = 0; scatterViewItem.Orientation = 0; scatterViewItem.DoubleTapped += new RoutedEventHandler(scatterViewItem_DoubleTapped); surfaceScatterViewer.Items.Add(scatterViewItem); } #endregion } } ``` ## LoadingUserControl.xaml ## ### LoadingUserControl.xaml ### <Touco_Shinning_Core_CustomControl:LoadingProgressUserControl Grid.Column="1" x:Name="loadingProgress"/> ### LoadingUserControl.xaml.cs ### namespace CFileWall { /// /// LoadingUserControl.xaml 的交互逻辑 /// public partial class LoadingUserControl : UserControl { public event EventHandler LoadingCompleted; public LoadingUserControl() { InitializeComponent(); Loaded += new RoutedEventHandler(LoadingUserControl_Loaded); } void LoadingUserControl_Loaded(object sender, RoutedEventArgs e) { //启动新的线程加载文件 new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(delegate { int index = 1; if (App.Files == null) return; foreach (var file in App.Files) { this.Dispatcher.Invoke((Action)delegate { Console.WriteLine(index); textBlock_LoadingTips.Text = index.ToString() + @"/" + App.Files.Length.ToString(); loadingProgress.Value = (double)index / App.Files.Length * 100; }, null); Touco.Shinning.Core.Model.EnumClass.SurfaceFileType type = Touco.Shinning.Core.Model.SurfaceFileTypeConverter.Parse(file.FullName); App.FileModels[index - 1] = new Model.FileModel(file.FullName, type); System.Threading.Thread.Sleep(100); index++; } if (LoadingCompleted != null) { this.Dispatcher.BeginInvoke((Action)delegate { DispatcherTimer dt = new DispatcherTimer(); dt.Interval = TimeSpan.FromSeconds(1); dt.Tick += delegate { dt.Stop(); LoadingCompleted(this, null); }; dt.Start(); }, null); } })).Start(); } } } ## MainWindow.xaml ## ### MainWindow.xaml ### <Touco_Shinning_Core_CustomControl:AbstractItemWindow x:Class="CFileWall.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Touco_Shinning_Core_CustomControl="clr-namespace:Touco.Shinning.Core.CustomControl;assembly=Touco.Shinning.Core" xmlns:Local="clr-namespace:CFileWall" Title="MainWindow" WindowState="Maximized" WindowStyle="None"> ### MainWindow.xaml.cs ### namespace CFileWall { /// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Touco.Shinning.Core.CustomControl.AbstractItemWindow { public MainWindow() { InitializeComponent(); Loaded += delegate { //获取文件夹及其子文件夹下的所有符合条件的文件 App.Files = "*.png|*.jpg|*.jpeg|*.gif".Split('|').SelectMany(filter => new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures) + @"Sample Pictures").GetFiles(filter, SearchOption.AllDirectories)).ToArray(); List tempFileInfo = new List(); for (int i = 0; i < App.Files.Length; i++) { if(tempFileInfo.FirstOrDefault(_=>_.FullName.Equals(App.Files[i].FullName)) == null) { tempFileInfo.Add(App.Files[i]); } } App.FileModels = new Model.FileModel[App.Files.Length]; }; loadingUserControl.LoadingCompleted += delegate { MessageBox.Show("加载完毕"); this.Topmost = true; this.Topmost = false; this.grid_Root.Children.Remove(loadingUserControl); this.grid_Root.Children.Add(new FileWallUserControl()); }; } protected override void GetConfigFromArgs() { } } } ## ControlCSFileWallItemsControl.cs ## namespace CFileWall.Control.CS { /// /// 文件容器控件,实现自定义布局 /// public class FileWallItemsControl : ItemsControl { public const int ROWS = 3; public const int COLUMNS = 6; public const double TOPDISTANCE = 120D; public const double LEFTDISTANCE = 50D; private double m_VerticalDistance, m_HorizontalDistance; private double m_TempX = LEFTDISTANCE; private double m_TempY = TOPDISTANCE; private int m_TempIndex = 0; private Canvas m_ItemPanle; public FileWallItemsControl() { m_VerticalDistance = (ConstantClass.SysHeight - 2 * TOPDISTANCE - ROWS * ConstantClass.ELEMENTHEIGHT) / (ROWS - 1); m_HorizontalDistance = (ConstantClass.SysWidth - 2 * LEFTDISTANCE - COLUMNS * ConstantClass.ELEMENTWIDTH) / (COLUMNS - 1); Loaded += delegate { m_ItemPanle = Touco.Shinning.Core.UtilityFunctions.Sinnel.Util.WPFUtil.FindPanelForInternal(this) as Canvas; if (Items.Count % ROWS == 0) { m_ItemPanle.Width = m_TempX + LEFTDISTANCE; } else { m_ItemPanle.Width = m_TempX + LEFTDISTANCE + ConstantClass.ELEMENTWIDTH; } }; } protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { Model.FileModelContainer viewModel = e.NewItems[0] as Model.FileModelContainer; if (m_TempIndex % ROWS == 0) { m_TempX += m_HorizontalDistance + ConstantClass.ELEMENTWIDTH; m_TempY = TOPDISTANCE; } else m_TempY += m_VerticalDistance + ConstantClass.ELEMENTHEIGHT; viewModel.CanvasLeft = m_TempX; viewModel.CanvasTop = m_TempY; m_TempIndex++; } else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) { foreach (Model.FileModelContainer item in Items) { item.CanvasLeft = m_TempX; item.CanvasTop = m_TempY; m_TempIndex++; if (m_TempIndex % ROWS == 0) { m_TempX += m_HorizontalDistance + ConstantClass.ELEMENTWIDTH; m_TempY = TOPDISTANCE; } else m_TempY += m_VerticalDistance + ConstantClass.ELEMENTHEIGHT; } } base.OnItemsChanged(e); } } } ## ControlXAMLFileElementUserControl.xaml ## ### FileElementUserControl.xaml ### ### FileElementUserControl.xaml.cs ### namespace CFileWall.Control.XAML { /// /// FileElementUserControl.xaml 的交互逻辑 /// 单个文件 /// public partial class FileElementUserControl : UserControl { /// /// 文件名和预览图 /// public string Source { get { return (string)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(FileElementUserControl), new UIPropertyMetadata(string.Empty, (d, p) => { string fileName = p.NewValue.ToString(); if (System.IO.File.Exists(fileName)) { (d as FileElementUserControl).image_Displayer.Source = App.FileModels.Single(_ => _.FullName.Equals(fileName)).Thumbnail; (d as FileElementUserControl).textBlock_FileName.Text = new System.IO.FileInfo(fileName).Name.Remove(new System.IO.FileInfo(fileName).Name.LastIndexOf('.')); Console.WriteLine(App.FileModels.Single(_ => _.FullName.Equals(fileName)).IsResolvedSuccessfully.ToString()); } })); /// /// 文件类型,如果是Video,则显示播放按钮 /// public Touco.Shinning.Core.Model.EnumClass.SurfaceFileType Type { get { return (Touco.Shinning.Core.Model.EnumClass.SurfaceFileType)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(Touco.Shinning.Core.Model.EnumClass.SurfaceFileType), typeof(FileElementUserControl), new UIPropertyMetadata(Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Video, (d, p) => { if ((Touco.Shinning.Core.Model.EnumClass.SurfaceFileType)p.NewValue != Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Video) { (d as FileElementUserControl).image_PlayerButton.Visibility = Visibility.Hidden; } })); public FileElementUserControl() { InitializeComponent(); } protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) { //return base.HitTestCore(hitTestParameters); return new PointHitTestResult(this, hitTestParameters.HitPoint); } } } ## ModelFileModel.cs ## namespace CFileWall.Model { /// /// 文件模型类 /// public class FileModel { /// /// 文件全路径 /// private string _fullName = string.Empty; public string FullName { get { return _fullName; } } /// /// 文件类型 /// public Touco.Shinning.Core.Model.EnumClass.SurfaceFileType FileType { get; private set; } /// /// 缩略图 /// public BitmapSource Thumbnail { get; set; } /// /// 是否取得缩略图 /// public bool IsResolvedSuccessfully { get; private set; } public bool IsOfficeToXpsSuccessfully { get; private set; }//office转换xps文档是否成功 public FileModel(string fullName, Touco.Shinning.Core.Model.EnumClass.SurfaceFileType fileType) { _fullName = fullName; FileType = fileType; switch (FileType) { case Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Image: ResolveImage(); break; case Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Video: ResolveVideo(); break; case Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Office: //ResolveOfficeUsingIcon(); break; default: //ResolveUnknown(); break; } } private void ResolveImage() { BitmapSource bitmap = null; if (Touco.Shinning.Core.UtilityFunctions.Sinnel.Util.Folder.Folder.GetFileThumb(FullName, out bitmap)) { Thumbnail = bitmap; IsResolvedSuccessfully = true; } //BitmapSource bitmap = GetThumbnail(FullName); //if (bitmap != null) //{ // Thumbnail = bitmap; // IsResolvedSuccessfully = true; //} } private void ResolveVideo() { string tempXpsDirectory = GlobalEnvironment.GetPath(GlobalEnvironment.SpecialFolder.TempXPSFolder); if (!Directory.Exists(tempXpsDirectory)) { File.Create(tempXpsDirectory); } } private void ResolveOffice() { string tempXpsDirectory = GlobalEnvironment.GetPath(GlobalEnvironment.SpecialFolder.TempXPSFolder); if (!Directory.Exists(tempXpsDirectory)) { File.Create(tempXpsDirectory); } } public BitmapSource GetThumbnail(string file) { var decoder = BitmapDecoder.Create(new Uri(file), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None); var frame = decoder.Frames.FirstOrDefault(); return (frame.Thumbnail == null) ? null : frame.Thumbnail; } } } ## ModelFileModelContainer.cs ## namespace CFileWall.Model { /// /// 文件模型容器 /// public class FileModelContainer : Touco.Shinning.Core.Model.AbstractViewModelBase { /// /// 文件 /// private FileModel m_FileModel; public string Source { get { return (string)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(FileModelContainer), new UIPropertyMetadata(string.Empty)); public Touco.Shinning.Core.Model.EnumClass.SurfaceFileType Type { get { return (Touco.Shinning.Core.Model.EnumClass.SurfaceFileType)GetValue(TypeProperty); } set { SetValue(TypeProperty, value); } } public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type", typeof(Touco.Shinning.Core.Model.EnumClass.SurfaceFileType), typeof(FileModelContainer), new UIPropertyMetadata(Touco.Shinning.Core.Model.EnumClass.SurfaceFileType.Video)); public FileModelContainer(FileModel fileModel) { m_FileModel = fileModel; Source = m_FileModel.FullName; Type = m_FileModel.FileType; Width = CFileWall.Tools.ConstantClass.ELEMENTWIDTH; Height = CFileWall.Tools.ConstantClass.ELEMENTHEIGHT; } protected override void OnLoaded(Touco.Shinning.Core.UtilityFunctions.Sinnel.Mvvm.Command.CommandParameter param) { base.OnLoaded(param); } } } ## ToolsConstantClass.cs ## namespace CFileWall.Tools { /// /// 常量类,保存的都是程序需要的常量 /// public class ConstantClass { /// /// 文件宽度 /// public const double ELEMENTWIDTH = 301D; /// /// 文件高度 /// public const double ELEMENTHEIGHT = 247D; /// /// 配置文件路径 /// public static string ConfigFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config"); public static string Tag { get; set; } public static bool IsSetting { get; set; } public static string[] Args; /// /// 默认分辨率 /// internal const double SysWidth = 1920D; internal const double SysHeight = 1080D; } } 有问题或建议请反馈到: 微博 :[@Changweihua](http://weibo.com/changweihua) 邮箱 :changweihua@outlook.com