I have a 2 level WPF treeview. When I click on a child item, the correct selectedCommand is triggered and all works well.
But when I click on my details view and update the field of this selected item, it unselect my childItem and fired the parent command because the parent is selected, but I need to just keep my childItem selected.
I have found some topics about the same problem, but I use command for my binding and not just code behind so I don't know how to make this solution work for me.
- Dispacher.BeginInvoke method : > Parent TreeView Item ghost selected event!
- e.Handled : > WPF TreeviewItem parent selected event fired after selecting a child?
- And a topic that said it's a focus problem : TreeView auto-selecting parent after user selects child
Trigger of my command :
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction
Command="{Binding ItemSelectedCommand}"
CommandParameter="{Binding SelectedItem, ElementName=TreeView}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
My Treeview :
<TreeView x:Name="TreeView"
ItemsSource="{Binding Modules}">
<HierarchicalDataTemplate DataType="{x:Type module:ParentViewModel}" ItemsSource="{Binding ChildItems}">
<TextBlock Text="Parent"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type module:ChildViewModel}">
<TextBlock Text="{Binding Path=childName}"/>
</HierarchicalDataTemplate>
</TreeView>
And here is my command which is in my ViewModel file
public ICommand ItemSelectedCommand
{
get
{
return _itemSelectedCommand ?? (_itemSelectedCommand = new CommandHandler(param => SelectedCommand(param)));
}
}
public void SelectedCommand(object selectedItem)
{
//code to activate my details view with prism
if(selectedItem.GetType().Name == "ParentType")
{
ActivateParentView();
}
else
{
ActivateDetailsView(.....); //activate child view
}
}
So, I trigger the same command when selected an item in my treeview but when I select the child item, the parent event is also triggered so my command is triggered 2 times and activate my parent view and don't stay in my child view. How can I stop propagating the event if I have already pass through child command ? How can I make it working with my command and not in code behind ?
EDIT
Here is my function ActivateDetailsView() which is called by my SelectedCommand I have 13 modules and I have one detailsView in each module, so when I click on my selected item, I will search using reflexivity for the view I need to activate and I use PRISM library to activate it.
private void ActivateDetailsView(string nameTypeItem,IRegion tabConfigurationRegion, ModuleItemBaseViewModel selectedItem)
{
try
{
string viewName = "ModuleItem" + nameTypeItem + "DetailsView";
string moduleName = "Module" + nameTypeItem;
string fullViewName = moduleName + ".Views." + viewName + ", " + moduleName;
var typeOfCurrentView = Type.GetType(fullViewName);
//var view = Activator.CreateInstance(typeOfCurrentView);
var view = tabConfigurationRegion.GetView(viewName);
if (view == null)
{
view = _container.Resolve(typeOfCurrentView);
// Add the view to the main region. This automatically activates the view too.
tabConfigurationRegion.Add(view, viewName);
}
// The view has already been added to the region so just activate it.
tabConfigurationRegion.Activate(view);
string viewModelName = "ModuleItem" + nameTypeItem + "DetailsViewModel";
string fullViewModelName = moduleName + ".ViewModels." + viewModelName + ", " + moduleName;
var typeOfCurrentViewModel = Type.GetType(fullViewModelName);
//equivalent to ModuleItemSiemensDetailsViewModel viewModelM = view.DataContext as ModuleItemSiemensDetailsViewModel;
var propertyInfoDataContext = view.GetType().GetProperty("DataContext");
var viewModelModuleItem = propertyInfoDataContext.GetValue(view, null);
if (viewModelModuleItem != null)
{
PropertyInfo prop = typeOfCurrentViewModel.GetProperty("CurrentModuleItem");
//equivalent to viewModelModuleItem.CurrentModuleItem = selectedItem as ModuleItemBaseViewModel;
prop.SetValue(viewModelModuleItem, selectedItem, null);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
}
}
To reproduce the problem : Start a new WPF project, Add one main project in your solution with a view with a treeview and a treeviewviewmodel with the list of ParentViewModel which will be display on your treeview. Define an other project with 2 viewmodels : one class ParentVM with an ObservableCollection and a childViewModel, let one or two property like name, and bind it to the treeview. In the second project, define a detailsView to see properties of your ChildViewModel. On your main project, in the treeviewviewmodel add a SelectedCommandFunction which use prism to activate your detailView. (You need to have a DetailsView when you click on the Parent and an other one when you click on the ChildView.
Application.Current.Dispatcher.Invoke
to reset it) during update. – Sinatr<StackPanel> <TextBlock Text="Name:" /> <TextBox Text="{Binding Path=CurrentModuleItem.Name}" /> </StackPanel>
. I will just add my real function which activate the view because it use PRISM for it and maybe it's the way I am using prism which is incorrect ... – Karakayn