Reputation: 354
I have a TreeView of DirectoryItems that are defined like this:
public class DirectoryItem : INotifyPropertyChanged
{
public String DisplayName { get; set; }
public String Fullpath { get; set; }
public ObservableCollection<DirectoryItem> Children { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
When the user selects a DirectoryItem from the treeView, I want to take the Fullpath from that item, read all the text from the file, and load it into a text editor.
My ViewModel has a DisplayText property that the text editor is bound to:
internal class MainWindowViewModel : IMainWindowViewModel
{
private ObservableCollection<DirectoryItem> DirectoryItems { get; set; }
public string DisplayText { get; set; }
//this needs to be implemented to take a filepath and read from it
}
I think there should be a command called that is associated to the TreeViewItem's IsSelected property that passes the Fullpath to the ViewModel, but I haven't been able to get the code working. How would I implement this?
Here's what I have that I can't get working, I get a "Property triggers is not attachable to elements of type Style" error:
<Style TargetType="{x:Type TreeViewItem}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding DisplayText}" CommandParameter="{Binding ElementName=treeView, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Style>
Thank you.
Upvotes: 0
Views: 258
Reputation: 169228
You can't add an interaction trigger inside a Style
.
What you could do is to add an IsSelected
property to your DirectoryItem
class and bind the IsSelected
property of the TreeViewItem
to this one:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
public class DirectoryItem : INotifyPropertyChanged
{
public String DisplayName { get; set; }
public String Fullpath { get; set; }
public ObservableCollection<DirectoryItem> Children { get; set; }
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Make sure that you actually raise the PropertyChanged
property whenever the IsSelected
is set to a new value.
The view model could then hook up to the PropertyChanged
event of each item in the ObservableCollection<DirectoryItem>
and do something whenever an item is selected:
internal class MainWindowViewModel : IMainWindowViewModel
{
public MainWindowViewModel()
{
//add the items...
DirectoryItems.Add(new DirectoryItem() { DisplayName = "test", Children = new ObservableCollection<DirectoryItem>() { new DirectoryItem() { DisplayName = "child" } } });
foreach(var item in DirectoryItems)
{
item.PropertyChanged += Item_PropertyChanged;
}
}
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "IsSelected")
{
DirectoryItem selectedItem = sender as DirectoryItem;
//set the DisplayText property
}
}
public ObservableCollection<DirectoryItem> DirectoryItems { get; set; } = new ObservableCollection<DirectoryItem>();
public string DisplayText { get; set; }
}
If you are adding items dynamically to the ObservableCollection<DirectoryItem>
you probably also want to handle the CollectionChanged
event to hook up event handlers to any new objects as well:
private void DirectoryItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (object item in e.NewItems)
{
(item as INotifyPropertyChanged).PropertyChanged
+= new PropertyChangedEventHandler(Item_PropertyChanged);
}
}
if (e.OldItems != null)
{
foreach (object item in e.OldItems)
{
(item as INotifyPropertyChanged).PropertyChanged
-= new PropertyChangedEventHandler(Item_PropertyChanged);
}
}
}
Upvotes: 1