天天看點

基于WPF圖像處理Demo軟體(一)WPF控件模版TreeView

WPF控件模版TreeView

  1. 整個Demo效果圖。
    基于WPF圖像處理Demo軟體(一)WPF控件模版TreeView
  2. 前言

    最近準備接觸圖像處理領域的東西,想想還是從opencv開始學習,看到模闆比對的時候忍不住想動手實作之間接觸的一個項目,因某些原因圖像的來源是從CSharp程式裡實作的,是以得轉到C++裡面調用opencv處理,但是到選取模闆區域有點麻煩了,wpf自帶的image控件并不支援選區的編輯,而且還有坐标、RGB等重要資訊輸出,就動手Do It!

  3. 感謝

    首先這裡參閱了好多大神的例子,包括這個主界面(論壇大神用純C/C++實作基礎的圖像處理功能,簡直是我等楷模!),站在别人的肩膀上果然不腰疼。。。

  4. 正題

    架構介紹下,左邊是TreeViee控件,反射的自己磁盤目錄檔案,如果是檔案的話隻區分兩種,圖檔檔案和非圖檔檔案,本軟體僅處理圖像檔案(bmp、jpg、png);右邊為圖像控件,能實作滑鼠操作,縮放、拖動、實時顯示位置和RGB、局部放大、選取編輯(僅以三種形狀Demo)等功能。

    • TreeView控件

      添加節點選中的屬性,對外通知選中的檔案路徑(參閱)。

class MyTreeView : TreeView
    {
        public MyTreeView() : base()
        {
            this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(___ICH);
        }

        void ___ICH(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            if (SelectedItem != null)
            {
                //将SelectedItem通知到SelectedItem_Property也就是代理屬性SelectedItem_,以便往外傳播
                SetValue(SelectedItem_Property, SelectedItem);
            }
        }

        public object SelectedItem_
        {
            get { return (object)GetValue(SelectedItem_Property); }
            set { SetValue(SelectedItem_Property, value); }
        }
        public static readonly DependencyProperty SelectedItem_Property = DependencyProperty.Register("SelectedItem_", typeof(object), typeof(MyTreeView), new UIPropertyMetadata(null));
    }
           

在設計節點時,設計屬性目前目錄所有元素資訊:路徑、元素名稱、元素圖示、下一層路徑元素清單

class BindDirectory
    {
        static readonly string[] Imageforamt = new[] { ".bmp", ".jpg", ".png" };
        private List<BindDirectory> _directories;
        public string Name { get; private set; }
        public string Path { get; private set; }
        public ImageSource Icon { get; private set; }
        public BindDirectory(string directoryPath)
        {
            //正規化目錄路徑,確定Path以'\\'結尾
            directoryPath = directoryPath.TrimEnd('\\');
            Path = directoryPath + '\\';
            int indexLastSlash = directoryPath.LastIndexOf('\\');//計算出目錄名稱(不包含路徑)
            Name = indexLastSlash >= 0 ? directoryPath.Substring(indexLastSlash + 1) : directoryPath;
            Icon = new BitmapImage(new Uri("pack://application:,,,/images/Floder.png"));
        }
        public BindDirectory(FileInfo info)
        {
            Name = info.Name;
            Path = info.FullName;
            if (Imageforamt.Contains(info.Extension.ToLower()))
                Icon = new BitmapImage(new Uri("pack://application:,,,/images/image.png"));
            else
                Icon = new BitmapImage(new Uri("pack://application:,,,/images/file.png"));
        }

        public IEnumerable<BindDirectory> Directories
        {
            get
            {
                if (_directories == null) //延遲加載
                {
                    _directories = new List<BindDirectory>();
                    foreach (string d in Directory.GetDirectories(Path))
                        _directories.Add(new BindDirectory(d));
                    foreach (var f in Directory.GetFiles(Path))
                        _directories.Add(new BindDirectory(new FileInfo(f)));
                }
                return _directories;
            }
        }
        public static bool ValidImageFile(string path)
        {
            return Imageforamt.Contains(new FileInfo(path).Extension.ToLower());
        }
        public override string ToString()
        {
            return Path;
        }
    }
    
           
這裡要注意的是當選擇某一目錄(滑鼠選中)時,需要讀出該路徑下層元素資訊,第一層由磁盤管理器讀取各個磁盤資訊。
           
foreach (var drive in DriveInfo.GetDrives())
            {
                Add(new BindDirectory(drive.RootDirectory.FullName));
            }
           

然後設計TreeViewItem的樣式,每一層需要三個元素,左邊圖示折疊展開,右邊元素圖示(檔案、檔案夾),元素名稱,網上摘錄了一個第三方的Style

<Style  x:Key="DefaultTreeViewItem" TargetType="{x:Type TreeViewItem}">
           <Setter Property="MinHeight" Value="25" />
           <Setter Property="Foreground" Value="Black" />
           <Setter Property="Background" Value="Transparent" />
           <Setter Property="SnapsToDevicePixels" Value="True" />
           <Setter Property="Margin" Value="0" />
           <Setter Property="Template">
               <Setter.Value>
                   <ControlTemplate TargetType="{x:Type TreeViewItem}">
                       <StackPanel>
                           <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
                               BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"
                               MinHeight="{TemplateBinding MinHeight}" UseLayoutRounding="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                               <!--多層級間隔,暫緩-->
                               <!--<Grid Margin="{Binding Converter={StaticResource LengthConverter}, RelativeSource={x:Static RelativeSource.TemplatedParent}}"-->
                               <Grid Margin="{TemplateBinding Margin}" VerticalAlignment="Stretch">
                                   <Grid.ColumnDefinitions>
                                       <ColumnDefinition MinWidth="18" Width="Auto" />
                                       <ColumnDefinition Width="*" />
                                   </Grid.ColumnDefinitions>
                                   <!--展開收縮按鈕-->
                                   <ToggleButton x:Name="ExpanderBtn" 
                                             IsChecked="{Binding Path=IsExpanded, RelativeSource={x:Static RelativeSource.TemplatedParent}, Mode=TwoWay}"
                                             ClickMode="Press" >
                                       <ToggleButton.Template>
                                           <ControlTemplate TargetType="ToggleButton">
                                               <Border>
                                                   <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                               </Border>
                                           </ControlTemplate>
                                       </ToggleButton.Template>
                                       <ToggleButton.Content>
                                           <Image x:Name="ExpanderIcon"/>
                                           <!--<TextBlock x:Name="ExpanderIcon"  Foreground="{TemplateBinding Foreground}" Text="&#xe62c;"  Style="{StaticResource FIcon}" />-->
                                       </ToggleButton.Content>
                                   </ToggleButton>
                                   <!--内容-->
                                   <ContentPresenter x:Name="PART_Header" Grid.Column="1" ContentSource="Header"
                                                 SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                 VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                               </Grid>
                           </Border>
                           <ItemsPresenter Margin="18,0,0,0" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                       </StackPanel>
                       <ControlTemplate.Triggers>
                           <Trigger Property="IsExpanded" Value="False">
                               <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
                               <Setter TargetName="ExpanderIcon" Property="Source" Value="pack://application:,,,/images/expand-right.png" />
                           </Trigger>
                           <Trigger Property="IsExpanded" Value="True">
                               <Setter TargetName="ExpanderIcon" Property="Source" Value="pack://application:,,,/images/expand-down.png" />
                           </Trigger>
                           <Trigger Property="HasItems" Value="False">
                               <Setter TargetName="ExpanderIcon" Property="Visibility" Value="Hidden" />
                           </Trigger>
                           <Trigger Property="IsMouseOver" Value="True">
                               <Setter Property="Background" Value="{StaticResource ItemMouseOverBackground}" />
                               <Setter Property="Foreground" Value="{StaticResource ItemMouseOverForeground}" />
                           </Trigger>
                           <Trigger Property="IsSelected" Value="True">
                               <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                               <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" />
                           </Trigger>
                           <MultiTrigger>
                               <MultiTrigger.Conditions>
                                   <Condition Property="IsSelected" Value="True" />
                                   <Condition Property="Selector.IsSelectionActive" Value="True" />
                               </MultiTrigger.Conditions>
                               <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                               <Setter Property="Foreground" Value="{StaticResource ItemSelectedForeground}" />
                           </MultiTrigger>
                       </ControlTemplate.Triggers>
                   </ControlTemplate>
               </Setter.Value>
           </Setter>
       </Style>
           

關于模闆的概念參閱

1.https://www.cnblogs.com/zhili/p/WPFTemplate.html; 2.https://www.cnblogs.com/dingli/archive/2011/07/20/2112150.html#top;

ToggleButton 控件模闆決定了Content展開收縮的外觀均為居中,Content為一個Image控件來顯示展開收縮的圖示,圖示切換的邏輯放模闆觸發器内;第二列為元素名稱,使用ContentPresenter顯示目前元素内容,ItemsPresenter顯示子元素内容。

基于WPF圖像處理Demo軟體(一)WPF控件模版TreeView

小結(本文主要内容為加深對WPF模版控件的了解):

1.使用HierarchicalDataTemplate繼承與DataTemplate作為TreeViewItem和MenuItem的主要資料模闆,這裡設計顯示目前目錄的名稱和圖示;

2.使用ObjectDataProvider實作在xaml中執行個體化資料源,并可接受執行個體的方法、屬性等資料綁定,這裡利用構造函數将資料源(磁盤的集合)綁定到ItemSource;

基于WPF圖像處理Demo軟體(一)WPF控件模版TreeView
  • 未完待續。。。

繼續閱讀