防止树视图中的自动水平滚动不起作用.MVVM,XAML 方法
本文关键字:不起作用 滚动 MVVM 方法 XAML 水平 视图 | 更新日期: 2023-09-27 18:18:25
每当在我的树视图中选择一个节点时,它都会自动水平滚动到该项目。我已经找到了禁用此功能的方法。 如果我在代码隐藏中使用此代码,它可以完美运行:
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<EventSetter Event="RequestBringIntoView" Handler="TreeViewItem_RequestBringIntoView"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
private void TreeViewItem_RequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
但是,如果我使用 MVVM,则无法禁用水平滚动到该项目:
我的窗口:
<Window x:Class="TreeViewWpfApplication.MainWindow"
. . . . .
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei=http://schemas.microsoft.com/expression/2010/interactions>
<TreeView Grid.Column="1" Margin="5" Background="Green">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RequestBringIntoView">
<ei:CallMethodAction MethodName="RequestBringIntoView_Handler" TargetObject="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TreeView>
<TreeViewItem Header="---Level 1" >
<TreeViewItem Header="--- Level 2.1" >
<TreeViewItem Header="--- Level 3.1" >
</TreeViewItem>
</TreeViewItem>
</TreeViewItem>
<TreeViewItem Header="Level 2.3" />
</TreeView>
</Window>
视图模型:
public void RequestBringIntoView_Handler(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
为什么我无法通过 MVVM 方法停止自动水平滚动到项目?
我相信您始终可以遍历TreeView
的所有TreeViewItem
,并从TreeView
上附加的Interaction.Triggers
克隆每个TriggerBase
,然后再将每个克隆的附加到每个TreeViewItem
的Interaction.Triggers
。
我对Microsoft感到非常失望,自从我开始学习如何编程以来,这个名字让我感到自豪,多年来一直是我无尽的灵感。但坦率地说,有很多事情让我们失望Microsoft。您的代码实际上应该工作正常。为什么?我已经尝试过了,事件实际上RequestBringIntoView
从TreeViewItem
冒泡到TreeView
。事实上,当您直接在TreeView
上添加事件处理程序时,您将看到事件处理程序已正常触发。但是使用 Interaction
设置处理程序的等效形式并非如此。这太可怕了。很明显,它旨在以 MVVM 方式设置事件处理程序,但它非常有限。
我必须做一个变通办法,我们使用自定义附加属性来允许在 Style 中设置Interaction.Triggers
。但是我不得不说它不是很漂亮。您需要显式声明TriggerBase
的Array
(我以前做过这样的事情,但从未找到更好的解决方案(。接下来,您需要使用代理来绑定TargetObject
以进行EventTrigger
(因为我们将触发器放在数组中,并且它与可视化树分离(。
下面是自定义附加属性的代码:
//add some using alias like this first
//using i = System.Windows.Interactivity;
public static class InteractionX
{
public static readonly DependencyProperty TriggersProperty
= DependencyProperty.RegisterAttached("Triggers", typeof(i.TriggerBase[]),
typeof(InteractionX), new PropertyMetadata(triggersChanged));
public static i.TriggerBase[] GetTriggers(DependencyObject o){
return o.GetValue(TriggersProperty) as i.TriggerBase[];
}
public static void SetTriggers(DependencyObject o, i.TriggerBase[] value)
{
o.SetValue(TriggersProperty, value);
}
static void triggersChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var triggers = e.NewValue as i.TriggerBase[];
var currentTriggers = i.Interaction.GetTriggers(o);
currentTriggers.Clear();
foreach (var t in triggers)
{
t.Detach();
currentTriggers.Add(t);
}
}
}
下面是 XAML:
<TreeView>
<TreeView.Resources>
<DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding}"/>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="local:InteractionX.Triggers">
<Setter.Value>
<x:Array Type="{x:Type i:TriggerBase}">
<i:EventTrigger EventName="RequestBringIntoView">
<ei:CallMethodAction MethodName="bringIntoViewHandler"
TargetObject="{Binding Value, Source={StaticResource proxy}}"/>
</i:EventTrigger>
</x:Array>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
似乎在TreeViewItem
上设置的Interaction.Triggers
可以处理来自后代 TreeViewItems 的冒泡RequestBringIntoView
,但正如我所说,遗憾的是将其设置为TreeView
不起作用。