我尝试将展开的事件绑定到viewmodel(而不是* .xaml.cs文件),以便仅在展开节点后扩展树视图。
我的方法是:
<TreeView x:Name="TreeViewTest" ItemsSource="{Binding Items}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children, Mode=OneTime}">
<StackPanel>
<Label Content="{Binding Title, Mode=OneTime}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TreeViewItem.Expanded">
<i:InvokeCommandAction Command="{Binding DataContext.ExpandedCommand, Source={x:Reference TreeViewTest}}"> </i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
我收到以下错误消息:
由于周期性依赖性,无法调用MarkupExtension.ProvideValue。 MarkupExtension中的属性不能引用引用MarkupExtension结果的对象。受影响的MarkupExtensions是: System.Windows.Data.Binding
有人可以帮我解决这个错误,还是有另一种方法将事件绑定到viewmodel中的命令?
答案 0 :(得分:2)
我可以理解您尝试将命令附加到TreeViewItem.Expanded事件。 我已经就这个问题进行了一项小型研究,这是我最终得到的结果。
首先是TreeViewItem风格的AttachedProperties,这里是链接: Invoke Command when TreeViewItem is Expanded
其次是涉及行为的解决方案:
XAML:
<Grid>
<TreeView x:Name="TreeViewTest" ItemsSource="{Binding Items}" TreeViewItem.Expanded="TreeViewTest_OnExpanded">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type soTreeViewHelpAttempt:TreeObject}"
ItemsSource="{Binding Children, Mode=OneTime}">
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding }" />
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<StackPanel>
<Label Content="{Binding Title, Mode=OneTime}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<i:Interaction.Behaviors>
<soTreeViewHelpAttempt:TreeViewItemExpandBehavior OnExpandedAction="{Binding OnExpandedActionInViewModel}"/>
</i:Interaction.Behaviors>
</TreeView></Grid>
视图模型:
public MainDataContext()
{
OnExpandedActionInViewModel = new Action<object, RoutedEventArgs>(OnExpanded);
}
public Action<object, RoutedEventArgs> OnExpandedActionInViewModel
{
get { return _onExpandedActionInViewModel; }
private set
{
_onExpandedActionInViewModel = value;
OnPropertyChanged();
}
}
行为命令属性:
public static readonly DependencyProperty OnExpandedActionProperty = DependencyProperty.Register(
"OnExpandedAction", typeof (Action<object,RoutedEventArgs>), typeof (TreeViewItemExpandBehavior), new PropertyMetadata(default(Action<object,RoutedEventArgs>)));
public Action<object,RoutedEventArgs> OnExpandedAction
{
get { return (Action<object,RoutedEventArgs>) GetValue(OnExpandedActionProperty); }
set { SetValue(OnExpandedActionProperty, value); }
}
行为代码:
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObjectOnLoaded;
}
private void AssociatedObjectOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var treeView = sender as TreeView;
if(treeView == null) return;
treeView.ItemsSource.Cast<object>().ToList().ForEach(o =>
{
var treeViewItem = treeView.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem;
if(treeViewItem == null) return;
treeViewItem.Expanded += TreeViewItemOnExpanded;
_list.Add(treeViewItem);
});
}
private void TreeViewItemOnExpanded(object sender, RoutedEventArgs routedEventArgs)
{
if(OnExpandedAction == null)
return;
OnExpandedAction(sender, routedEventArgs);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Loaded -= AssociatedObjectOnLoaded;
_list.ForEach(item => item.Expanded -= TreeViewItemOnExpanded);
_list.Clear();
}
我希望它会对你有所帮助。 的问候,
答案 1 :(得分:1)
要创建绑定到TreeView,您必须使用RelativeSource Self,但不能使用Source with x:Reference。 例如,我将TreeView的宽度绑定到高度:
<TreeView Name="tv" Width="{Binding Height, RelativeSource={RelativeSource Self}}">
</TreeView>
或者您也可以使用ElementName,如下所示:
<TreeView Name="tv" Width="{Binding Height, ElementName=tv}">
</TreeView>
答案 2 :(得分:0)
我知道这个问题很老,但有一个不需要任何自定义代码的明显解决方案。
当使用 i:EventTrigger
时,您可以指定监听事件的对象,如下所示,我使用 RelativeSource
绑定在可视化树中向上走并找到 TreeViewItem
。
此外,您可以使用 ElementName
按名称绑定到元素,这不会导致循环依赖,因为当控件已经创建和初始化时绑定在调度程序上工作(不像 x:Reference
,它必须在 XAML 反序列化期间解析)。
<i:Interaction.Triggers>
<i:EventTrigger SourceObject="{Binding RelativeSource={RelativeSource AncestorType=TreeViewItem}}" EventName="Expanded">
<i:InvokeCommandAction Command="{Binding ElementName=TreeView, Path=DataContext.ExpandedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>