我正在尝试从TreeView中获取选定的项目,但遇到了一些问题。
我正在关注MVVM架构。我的ViewModel包含我的模型中一个类的集合。因此,我已将TreeView的ItemSource与该集合绑定在一起。我想将TreeView的selectedItem绑定到绑定集合的项目。我怎么做?这是SelectedItem和IsSelected属性的代码。
private static sourceData _selectedItem = null;
/// <summary>
/// Selected Item in the tree
/// </summary>
public static sourceData SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
}
}
}
private bool _isSelected;
/// <summary>
/// Get/Set for Selected node
/// </summary>
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
if (_isSelected)
{
SelectedItem = this;
OnPropertyChanged("IsSelected");
}
}
}
}
/// <summary>
/// Property changed event
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Property changed event handler
/// </summary>
/// <param name="propertyName"></param>
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
当我调试它时,int SelectedItem = this;
'this'指针包含树状视图绑定到的集合。我需要一个SelectedDataSource,以便可以将其分配给选定的项目。如何使TreeView返回集合中的selectedItem?
FYi,这是我对TreeView的XAML代码
<TreeView Margin="5,0,0,0" ItemsSource="{Binding SourceData}" Width="390">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding DataContext.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Name="contextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" >
<MenuItem Name="menuItem" Header="Rename" Command="{Binding RenameCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
PS:如果我在模型中编写以上代码,我将一切正常运行。但是我不能在Model中编写以上代码,它必须在VM中。
关于您的问题的评论之后,WPF TreeView给MVVM开发人员带来了一些独特的挑战,其中包括检测当前选择的项目。为此,您可以使用附加的行为。首先,编写一个静态类来包含行为...
public static class TvBehaviour
{
#region TvSelectedItemChangedBehaviour (Attached DependencyProperty)
public static readonly DependencyProperty TvSelectedItemChangedBehaviourProperty =
DependencyProperty.RegisterAttached("TvSelectedItemChangedBehaviour",
typeof (ICommand),
typeof (TvBehaviour),
new PropertyMetadata(
OnTvSelectedItemChangedBehaviourChanged));
public static void SetTvSelectedItemChangedBehaviour(DependencyObject o, ICommand value)
{
o.SetValue(TvSelectedItemChangedBehaviourProperty, value);
}
public static ICommand GetTvSelectedItemChangedBehaviour(DependencyObject o)
{
return (ICommand) o.GetValue(TvSelectedItemChangedBehaviourProperty);
}
private static void OnTvSelectedItemChangedBehaviourChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
TreeView tv = d as TreeView;
if (tv != null)
{
tv.SelectedItemChanged += (s, a) =>
{
GetTvSelectedItemChangedBehaviour(tv).Execute(a.NewValue);
a.Handled = true;
};
}
}
#endregion
}
然后将类的名称空间导入Xaml(使用xmlns)。然后,您可以按照以下方式声明TreeView ...
<TreeView ItemsSource="{Binding MyList}"
ItemTemplate="{StaticResource My_data_template}"
tvBinding:TvBehaviour.TvSelectedItemChangedBehaviour="{Binding
SelectedItemCommand}"
SelectedValuePath="Name"
>
</TreeView>
这会将电视行为“链接”到您的VM中的ICommand。最后,在您的VM中声明ICommand ...
public ICommand SelectedItemCommand {get;组; }
并初始化...
SelectedItemCommand = new RelayCommand(ExecuteSelectedItemCommand,
CanExecuteSelectedItemCommand);
然后实现您的代表...
private void ExecuteSelectedItemCommand(object obj)
{
// downcast 'obj' to get the instance of the selected item
}
private bool CanExecuteSelectedItemCommand(object obj)
{
return true;
}
[当用户选择电视项目时,您的'执行'代表将获得该项目的装箱实例,您可以将其开箱等等”等等>
请注意,本示例中的附加行为假设电视的寿命与应用程序相同,否则您必须取消附加行为的连线。它还假定TV ItemsSource绑定到了一些明智的东西。
这将解决在保持MVVM兼容的同时获得TV SelectedItem的问题(如果存在符合MVVM的问题)。>>
我使用的Relay Command类来自MSDN中的链接文章。仅供参考,这里是...
public class RelayCommand : ICommand { //http://msdn.microsoft.com/en-us/magazine/dd419663.aspx public RelayCommand(Action<object> execute, Predicate<object> canExecute) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute(parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public void Execute(object parameter) { _execute(parameter); } private readonly Action<object> _execute; private readonly Predicate<object> _canExecute; }
使用上面的MSDN链接获取有关此类的更多信息。