2016-10-24 9 views
0

私はファイルをすばやく見つけて見るために何かを作成しようとしました。だから私はアイテムとしてStackPanelsを持っているTreeViewを作成しました。 StackPanelにはイメージとラベルが含まれています。スタックパネルの項目を持つツリービューを並べ替える方法

private TreeViewItem createFile(string Name, string soureFile) 
    { 
     TreeViewItem tvi = new TreeViewItem(); 
     StackPanel sp = new StackPanel(); 
     Image i = new Image(); 
     Label l_Text = new Label(); 
     Label l_FileName = new Label(); 

     l_FileName.Content = soureFile; 
     l_FileName.Width = 0; 
     l_Text.Content = Name; 

     System.Drawing.Bitmap dImg = (System.Drawing.Bitmap)Properties.Resources.ResourceManager.GetObject("Picture"); 
     MemoryStream ms = new MemoryStream(); 
     dImg.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 
     BitmapImage bImg = new BitmapImage(); 
     bImg.BeginInit(); 
     bImg.StreamSource = new MemoryStream(ms.ToArray()); 
     bImg.EndInit(); 
     i.Source = bImg; 
     i.Height = 20; 
     i.Width = 20; 

     sp.Name = "SP_File"; 
     sp.Orientation = Orientation.Horizontal; 
     sp.Children.Add(i); 
     sp.Children.Add(l_Text); 
     sp.Children.Add(l_FileName); 
     tvi.Header = sp; 

     return tvi; 
    } 

一つは、(単にHDD上の実際のファイルへの参照)(単に構造を作成するための)論理的なフォルダを作成したフォルダにファイルや他のフォルダを追加することができます。これは、私がTreeViewをソートしようとするまでうまくいきました。私はさらにそれはそう少しを読んで、私は私が「Header.StackPanel.Label.Text」 と交流「ヘッダ」をカント以来、明らかにこれは私のために動作しません

SortDescriptions.Add(new SortDescription("Header", ListSortDirection.Ascending)); 

でソートツリービューの上にものを読み私は、MVVM(Numerically sort a List of TreeViewItems in C#)を使用しないことで、全体に間違ったアプローチを使用しました。

私はMVVMで何の経験もしていないので、誰かがMVVMでこれを行うのが最善であると私に説明することができますか?私はファイルとフォルダを保持するために "watchedFile"のリストを使用します。

パスがnullであるか、そのフォルダを空にした場合、私は基本的にファイル

class watchedFile 
{ 
    public string name { get; private set; } 
    public string path { get; private set; } 
    public List<string> tags { get; private set; } 

    public watchedFile(string Name, string Path, List<string> Tags) 
    { 
     name = Name; 
     path = Path; 
     tags = Tags; 
    }   
} 

のための以下のクラスを持っています。 TreeViewItemには、小さな "フォルダ"または "画像"、 "watchedFile.name"を示すラベル、watchedfile.path(ツールチップとしてのみ表示される)を含む目に見えないラベルが表示されます。私はDataBindingでこれを行う必要があるので、目に見えないラベルを追加する必要はありません。

質問:

  1. どのように私はMVVMを使用してタスクを解決することができますか?
  2. 区別するためにwacthedFile.pathがある場合、どのようにしてImageをTreeViewItemにバインドできますか?
  3. 監視対象アイテムを並べ替えるにはどうすればよいですか?
  4. 保存されたファイルから構造を再構築できるように、ツリービューレベルをどのように追跡するのですか?
  5. MVVM /データバインディングを使用せずにStackPanel項目でTreeViewをソートする方法はありますか?

ご協力いただきまして誠にありがとうございます。

答えて

1

このMVVMファッションを行う方法は次のとおりです。

まず、viewmodelクラスを作成します。ここでは、WatchedFileインスタンスのコレクションを持つメインのビューモデルがあり、次にWatchedFileクラスがあります。また、文字列だけでなく、Tagをクラスにすることにしました。これにより、一般的な文字列ではなく、Tagのインスタンスを明示的かつ排他的に表示するXAMLにデータテンプレートを書き込むことができます。 UIは文字列でいっぱいです。

スニペットがない場合は、通知プロパティーの作成が面倒です。 I have snippets(それらを盗む!彼らは釘付けにされていない!)。

これを取得したら、並べ替えは大したことではありません。ルートレベルのアイテムを並べ替える場合は、WatchedFileです。

SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); 

ただし、以下のXAMLで説明します。

シリアライザもシンプルです。ビューモデルをシリアライズ可能にするだけです。ここで重要なことは、ソートとシリアライゼーションがツリービューアイテムテンプレートに何があるか気にする必要がないことです。 StackPanels、GroupBox、何でも - 大事なことではありません。ソートやシリアライゼーションコードはUIクラスではなくデータクラスを扱うためです。データテンプレートの視覚的な詳細は、コードの他の部分に影響を与えることを心配することなく、根本的に変更できます。それはMVVMについて素晴らしいことです。

のviewmodels:背後

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Linq; 
using System.Runtime.CompilerServices; 
using System.Text; 
using System.Threading.Tasks; 

namespace WatchedFile.ViewModels 
{ 
    public class ViewModelBase : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public class WatchedFile : ViewModelBase 
    { 
     #region Name Property 
     private String _name = default(String); 
     public String Name 
     { 
      get { return _name; } 
      set 
      { 
       if (value != _name) 
       { 
        _name = value; 
        OnPropertyChanged(); 
       } 
      } 
     } 
     #endregion Name Property 

     #region Path Property 
     private String _path = default(String); 
     public String Path 
     { 
      get { return _path; } 
      set 
      { 
       if (value != _path) 
       { 
        _path = value; 
        OnPropertyChanged(); 
       } 
      } 
     } 
     #endregion Path Property 

     #region Tags Property 
     private ObservableCollection<Tag> _tags = new ObservableCollection<Tag>(); 
     public ObservableCollection<Tag> Tags 
     { 
      get { return _tags; } 
      protected set 
      { 
       if (value != _tags) 
       { 
        _tags = value; 
        OnPropertyChanged(); 
       } 
      } 
     } 
     #endregion Tags Property 
    } 

    public class Tag 
    { 
     public Tag(String value) 
     { 
      Value = value; 
     } 
     public String Value { get; private set; } 
    } 

    public class MainViewModel : ViewModelBase 
    { 
     public MainViewModel() 
     { 
      Populate(); 
     } 

     public void Populate() 
     { 
      // Arbitrary test info, just for display. 
      WatchedFiles = new ObservableCollection<WatchedFile> 
      { 
       new WatchedFile() { Name = "foobar.txt", Path = "c:\\testfiles\\foobar.txt", Tags = { new Tag("Testfile"), new Tag("Text") } }, 
       new WatchedFile() { Name = "bazfoo.txt", Path = "c:\\testfiles\\bazfoo.txt", Tags = { new Tag("Testfile"), new Tag("Text") } }, 
       new WatchedFile() { Name = "whatever.xml", Path = "c:\\testfiles\\whatever.xml", Tags = { new Tag("Testfile"), new Tag("XML") } }, 
      }; 
     } 

     #region WatchedFiles Property 
     private ObservableCollection<WatchedFile> _watchedFiles = new ObservableCollection<WatchedFile>(); 
     public ObservableCollection<WatchedFile> WatchedFiles 
     { 
      get { return _watchedFiles; } 
      protected set 
      { 
       if (value != _watchedFiles) 
       { 
        _watchedFiles = value; 
        OnPropertyChanged(); 
       } 
      } 
     } 
     #endregion WatchedFiles Property 
    } 
} 

コード。注:ここでは、ウィザードが私に与えたものに1行追加しました。

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 WatchedFile 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      DataContext = new ViewModels.MainViewModel(); 
     } 
    } 
} 

そして最後にXAML:

<Window 
    x:Class="WatchedFile.MainWindow" 
    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:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" 
    xmlns:local="clr-namespace:WatchedFile" 
    xmlns:vm="clr-namespace:WatchedFile.ViewModels" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <CollectionViewSource 
       x:Key="SortedWatchedFiles" 
       Source="{Binding WatchedFiles}"> 
      <CollectionViewSource.SortDescriptions> 
       <scm:SortDescription PropertyName="Name" Direction="Ascending" /> 
      </CollectionViewSource.SortDescriptions> 
     </CollectionViewSource> 
    </Window.Resources> 
    <Grid> 
     <TreeView 
      ItemsSource="{Binding Source={StaticResource SortedWatchedFiles}}" 
      > 
      <TreeView.Resources> 
       <HierarchicalDataTemplate 
        DataType="{x:Type vm:WatchedFile}" 
        ItemsSource="{Binding Tags}" 
        > 
        <TextBlock 
         Text="{Binding Name}" 
         ToolTip="{Binding Path}" 
         /> 
       </HierarchicalDataTemplate> 
       <HierarchicalDataTemplate 
        DataType="{x:Type vm:Tag}" 
        > 
        <TextBlock 
         Text="{Binding Value}" 
         /> 
       </HierarchicalDataTemplate> 
      </TreeView.Resources> 
     </TreeView> 
    </Grid> 
</Window> 

XAMLが明らかに満ちません。 TreeView.Resourcesは、TreeViewの子の対象範囲に含まれています。 HierarchicalDataTemplateにはx:Keyプロパティがありません。暗黙的にになります。つまり、TreeViewのアイテムがインスタンス化されると、各ルートアイテムのDataContextのクラスインスタンスはWatchedFileになります。 WatchedFileには暗黙的なデータテンプレートがあるので、その内容を記入するために使用されます。 TreeViewは再帰型なので、DataTemplateの代わりにHierarchicalDataTemplateを使用します。 HierarchicalDataTemplateは、DataContextオブジェクトで子を探す場所を項目に指示するItemSourceプロパティを追加します。 WatchedFile.Tagsは、ルートレベルのツリー項目の場合はItemsSourceです。それらはTagであり、暗黙的にHierarchicalDataTemplateがあります。子供がいないので、HierarchicalDataTemplate.ItemsSourceは使用しません。

すべてのコレクションがObservableCollection<T>であるため、いつでもコレクションにアイテムを追加したり削除したりできます。UIは自動的に更新されます。 NamePathのプロパティをWatchedFileとすると、INotifyPropertyChangedが実装されており、値が変更されたときにそのプロパティの値が「PropertyChanged」になるので、同じことができます。 XAML UIは通知されずにすべての通知イベントにサブスクライブし、適切な処理を行います。

あなたの分離コードはFindResourceSortedWatchedFilesを取得し、そのSortDescriptionsを変更するが、それはあなたがツリービューを移入している方法については不可知論者だから、これは、私に多くの意味がありますすることができます:背後

<Button Content="Re-Sort" Click="Button_Click" HorizontalAlignment="Left" /> 

    <!-- ... snip ... --> 

    <TreeView 
     x:Name="WatchedFilesTreeView" 
     ...etc. as before... 

コード:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    var cv = CollectionViewSource.GetDefaultView(WatchedFilesTreeView.ItemsSource); 

    cv.SortDescriptions.Clear(); 
    cv.SortDescriptions.Add(
     new System.ComponentModel.SortDescription("Name", 
      System.ComponentModel.ListSortDirection.Descending)); 
} 
+0

非常に詳細な回答をいただきありがとうございます - 私は非常に好きです。それは今までにうまく動作し、私はMVVMにもう少し持ってきている。私はまだいくつかの問題を抱えています。私は、ファイル/フォルダ自体に複数のエントリがあるようにしたいと思います。だから私は監視されたコレクションをWatchedFileに追加しました – Thoms

+0

さらなる質問のために次の "答え"を見てください – Thoms

+1

申し訳ありませんが、正しく読み込めませんでした) 'ItemsSource =" {Binding Tags} "'を 'ItemsSource =" {Binding Subs} ' – Thoms

関連する問題