大部分时间我们在处理树的ItemChange或SelectionChanged时遇到问题。经过大量的努力,我找到了适合自己的解决方案。以下是答案
答案 0 :(得分:0)
使用下面附加的属性当选择树项或更改选择时,它会直接在该对象上引发命令
public class ControlBehaviour
{
private static IDictionary<object, ICommand> dataContextCommandMap = new Dictionary<object, ICommand>();
private static IDictionary<FrameworkElement, object> elementDataConextMap = new Dictionary<FrameworkElement, object>();
/// <summary>
///
/// </summary>
public static readonly DependencyProperty ControlEventProperty =
DependencyProperty.RegisterAttached("ControlEvent", typeof(RoutedEvent), typeof(ControlBehaviour),
new PropertyMetadata(OnTreeviewSelectionChanged));
/// <summary>
///
/// </summary>
/// <param name="target"></param>
/// <param name="value"></param>
public static void SetControlEvent(DependencyObject target, object value)
{
target.SetValue(ControlEventProperty, value);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <returns></returns>
public static RoutedEvent GetControlEvent(DependencyObject sender)
{
return sender.GetValue(ControlEventProperty) as RoutedEvent;
}
/// <summary>
/// Command to be executed
/// </summary>
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand),
typeof(ControlBehaviour), new PropertyMetadata(CommandChanged));
/// <summary>
/// Set ICommand to the dependency object
/// </summary>
/// <param name="target">dependency object</param>
/// <param name="value">I command</param>
public static void SetCommand(DependencyObject target, object value)
{
target.SetValue(CommandProperty, value);
}
/// <summary>
/// Get ICommand to the dependency object
/// </summary>
/// <param name="sender">dependency object</param>
/// <returns>ICommand of the dependency object</returns>
public static ICommand GetCommand(DependencyObject sender)
{
return sender.GetValue(CommandProperty) as ICommand;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnTreeviewSelectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender != null)
{
TreeView element = sender as TreeView;
if (element != null)
{
if (e.NewValue != null)
{
element.SelectedItemChanged += Handler;
}
if (e.OldValue != null)
{
element.SelectedItemChanged -= Handler;
}
}
}
}
/// <summary>
/// ICommand Changed
/// </summary>
/// <param name="sender">dependency object</param>
/// <param name="e">dependency args</param>
private static void CommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender != null)
{
FrameworkElement cntrl = sender as FrameworkElement;
if (cntrl != null && cntrl.DataContext != null)
{
if (e.NewValue != null)
{
ICommand cmd = e.NewValue as ICommand;
if (cmd != null)
{
elementDataConextMap[cntrl] = cntrl.DataContext;
dataContextCommandMap[cntrl.DataContext] = cmd;
}
}
cntrl.Unloaded += FrameworkElementUnloaded;
}
}
}
/// <summary>
/// Framework element unload, Clears the removes the ICommand
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void FrameworkElementUnloaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (element != null && elementDataConextMap.ContainsKey(element))
{
dataContextCommandMap.Remove(elementDataConextMap[element]);
elementDataConextMap.Remove(element);
}
}
/// <summary>
/// Routed Event Handler
/// </summary>
/// <param name="sender">sender</param>
/// <param name="e">EventArgs</param>
static void Handler(object sender, EventArgs e)
{
TreeView treeView = sender as TreeView;
if (treeView != null && treeView.SelectedItem != null && dataContextCommandMap.ContainsKey(treeView.SelectedItem)
&& dataContextCommandMap[treeView.SelectedItem].CanExecute(treeView.SelectedItem))
{
dataContextCommandMap[treeView.SelectedItem].Execute(treeView.SelectedItem);
}
}
}
以下是使用上述附加属性的XMAL
<TreeView Grid.Row="1" Background="Transparent" ItemsSource="{Binding Directories}" Margin="0,10,0,0" Name="FolderListTreeView"
Height="Auto" HorizontalAlignment="Stretch" Width="300" local:ControlBehaviour.ControlEvent="TreeView.SelectedItemChanged" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:FileSystem}" ItemsSource="{Binding SubDirectories}">
<Label Content="{Binding Path= Name}" Name="NodeLabel" local:ControlBehaviour.Command="{Binding OnSelect}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
下面是绑定在Xaml中的FileSystem类
/// <summary>
/// Implementation of file system class
/// </summary>
public class FileSystem :BindableBase, IFileSystem, IEnumerable //BindableBase is base class which implemets INotifyPropertyChanged
{
#region Private members
private ObservableCollection<IFileSystem> subDirectoriesField;
private ObservableCollection<IFileSystem> filesField;
#endregion
#region Public properties
/// <summary>
/// Gets and sets all the Files in the current folder
/// </summary>
public ObservableCollection<IFileSystem> SubDirectories
{
get
{
return subDirectoriesField;
}
set
{
if (subDirectoriesField != value)
{
subDirectoriesField = value;
NotifyPropertyChanged("SubDirectories");
}
}
}
/// <summary>
/// Gets and sets all the files in the current folder
/// </summary>
public ObservableCollection<IFileSystem> Files
{
get
{
return filesField;
}
set
{
if (filesField != value)
{
filesField = value;
RaisePropertyChanged("Files");
}
}
}
/// <summary>
/// Gets or sets the type of the file
/// </summary>
public FileSystemType FileType
{
get;
set;
}
/// <summary>
/// Gets or sets the size of the file
/// </summary>
public long Size
{
get;
set;
}
/// <summary>
/// Gets or sets name of the file system
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// Gets or sets full path of the file system
/// </summary>
public string FullPath
{
get;
set;
}
/// <summary>
/// object of parent, null if the current node is root
/// </summary>
public FileSystem Parent
{
get;
set;
}
/// <summary>
/// Returns ICommand
/// </summary>
public ICommand OnSelect
{
get
{
return new Command_R(Execute);//Command_R is implemention of your ICommand
}
}
#endregion
#region Constructor
/// <summary>
/// Constructor
/// </summary>
/// <param name="path">path of the folder</param>
/// <param name="parent">object of the parent</param>
public FileSystem(string fullPath, FileSystem parent, FileSystemType
type = FileSystemType.Directory)
{
Name = fullPath != null ? GetNameFileName(fullPath) : fullPath;
FullPath = fullPath;
Parent = parent;
FileType = type;
FilesAndSubDirectoriesDetails(fullPath);
}
#endregion
#region Public methods
/// <summary>
/// Updates the file size if there is a change
/// </summary>
/// <param name="deleteFilzeSize"></param>
public void UpdateFileSize(long deleteFilzeSize)
{
UpdatePredecessor(this, deleteFilzeSize);
}
/// <summary>
/// Gets the enumeration list
/// </summary>
/// <returns>returns the enumeration list</returns>
public IEnumerator GetEnumerator()
{
return SubDirectories.GetEnumerator();
}
#endregion
#region Private methods
/// <summary>
/// Finds the details of the files and sub directories
/// </summary>
/// <param name="fullPath"></param>
private void FilesAndSubDirectoriesDetails(string fullPath)
{
if (FileType.Equals(FileSystemType.Directory))
{
AddFilesAndSubDirectories(fullPath);
CalculateDirectorySize();
}
else
{
//Write code to calcuate the File Size
//Size = FileInfo.GetSize(fullPath);
}
}
/// <summary>
/// Finds and adds the files and sub directories
/// </summary>
/// <param name="fullPath"></param>
private void AddFilesAndSubDirectories(string fullPath)
{
string[] subDirectories = Directory.GetDirectories(fullPath);
SubDirectories = new ObservableCollection<IFileSystem>();
foreach (string directory in subDirectories)
{
SubDirectories.Add(new FileSystem(directory, this));
}
Files = new ObservableCollection<IFileSystem>();
string[] files = File.GetFiles(fullPath);
foreach (string fileName in files)
{
Files.Add(new FileSystem(fileName, this, FileSystemType.File));
}
}
/// <summary>
/// Calculates the current directory size
/// </summary>
private void CalculateDirectorySize()
{
foreach (FileSystem directory in SubDirectories)
{
Size += directory.Size;
}
foreach (FileSystem file in Files)
{
Size += file.Size;
}
}
/// <summary>
/// Updates the file size of the predecessors
/// </summary>
/// <param name="currentNode">current node</param>
/// <param name="deleteFilzeSize">file to be updated</param>
private void UpdatePredecessor(FileSystem currentNode, long deletedFilzeSize)
{
if (currentNode != null)
{
currentNode.Size -= deletedFilzeSize;
UpdatePredecessor(currentNode.Parent, deletedFilzeSize);
}
}
/// <summary>
/// Executes ICommand
/// </summary>
/// <param name="parameter">parameter</param>
private void Execute(object parameter)
{
//Do your Job
MessageBox.Show(FullPath);
}
#endregion
}
和班级的接口
/// <summary>
/// Type of the file
/// </summary>
public enum FileSystemType
{
/// <summary>
/// File
/// </summary>
File,
/// <summary>
/// Directory
/// </summary>
Directory
}
/// <summary>
/// Interface for File system
/// </summary>
public interface IFileSystem
{
/// <summary>
/// Gets or sets file type
/// </summary>
FileSystemType FileType
{
get;
set;
}
/// <summary>
/// Gets or sets the file size
/// </summary>
long Size
{
get;
set;
}
/// <summary>
/// Gets or sets name of the file system
/// </summary>
string Name
{
get;
set;
}
/// <summary>
/// Gets or sets full path of the file system
/// </summary>
string FullPath
{
get;
set;
}
}