【问题标题】:Can i call a function via DataTrigger (XAML)?我可以通过 DataTrigger (XAML) 调用函数吗?
【发布时间】:2014-09-25 11:18:13
【问题描述】:

我在 .xaml.cs 中有一个我想调用的函数:

.xaml.cs

private void treeView_SelectedItemChanged(object sender, EventArgs e)
{
        //treeView.ScrollToCenterOfView(sender as TreeViewItem);
}

喜欢这篇文章: Make ListView.ScrollIntoView Scroll the Item into the Center of the ListView (C#) 答案 1

但我不使用 SelectedItem,我的方法是:

XAML:

<Style.Triggers>
     <DataTrigger Binding="{Binding Path=IsActive}" Value="true">
          // ###call this function
     </DataTrigger>
</Style.Triggers>

我不知道如何通过更改 DataModel 来提高此功能。 在每个教程中,我都使用了他们通过事件/命令来完成。

谢谢

【问题讨论】:

  • 您使用的是 MVVM 模式还是纯代码隐藏方法?
  • 我试试 MVVM。但我对此很陌生

标签: c# wpf events command datatrigger


【解决方案1】:

只是为这些场景添加另一个稍微有点 hacky 的选项。

不完全是触发器,但您可以利用通用 FrameworkElement.Tag 属性为您要监视的属性设置绑定,然后在它发生更改时运行回调。

例如:

<DataTemplate>
    <StackPanel Tag="{Binding IsActive, NotifyOnTargetUpdated=True}"
                TargetUpdated="CodeBehindMethodToCall">

        <!-- snip rest of template --> 

    </StackPanel>
<DataTemplate>

【讨论】:

    【解决方案2】:

    这是我对带有 DataTrigger 的 Auto-ScrollItemToCenter TreeView 的解决方案,因此它不是滚动的选定项目。

    在 XAML 中,我通过 DataTrigger 添加了一个自定义行为

                    <Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=IsSelectedInGrid}" Value="true">
                                <Setter Property="local:TreeViewScrollBehavior.ScrollItemToCenter" Value="true" />
                            </DataTrigger>
                        </Style.Triggers>
    

    http://www.shujaat.net/2010/08/attached-behaviors.html 的这个简单示例之后,我尝试创建自己的行为

    public static class TreeViewScrollBehavior
    {
        public static DependencyProperty ScrollItemToCenterProperty =
    DependencyProperty.RegisterAttached("ScrollItemToCenter", typeof(bool),
    typeof(TreeViewScrollBehavior), new UIPropertyMetadata(false, OnScrollItemToCenter));
    
    
        public static bool GetScrollItemToCenter(DependencyObject obj)
        {
            return (bool)obj.GetValue(ScrollItemToCenterProperty);
        }
    
        public static void SetScrollItemToCenter(DependencyObject obj, bool value)
        {
            obj.SetValue(ScrollItemToCenterProperty, value);
        }
    
        public static void OnScrollItemToCenter(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
    
            if ((bool)e.NewValue)
            {
                //TreeViewItem t = GetTreeViewItem(d);
                TreeViewItem t = (TreeViewItem)d;
                TryScrollToCenterOfView(GetTree(t), t);
    
            }
        }
    

    并添加了上述链接的细微改动功能

        private static TreeView GetTree(TreeViewItem item)
        {
            var parent = VisualTreeHelper.GetParent(item);
            while (!(parent is TreeView))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent as TreeView;
        }
    
    
        private static void TryScrollToCenterOfView(ItemsControl itemsControl, UIElement container)
        {
            // Find the container
            //var container =  itemsControl.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
            if (container == null) return;
    
            // Find the ScrollContentPresenter
            ScrollContentPresenter presenter = null;
            for (Visual vis = container; vis != null && vis != itemsControl; vis = VisualTreeHelper.GetParent(vis) as Visual)
                if ((presenter = vis as ScrollContentPresenter) != null)
                    break;
            if (presenter == null) return;
    
            // Find the IScrollInfo
            var scrollInfo =
                !presenter.CanContentScroll ? presenter :
                presenter.Content as IScrollInfo ??
                FirstVisualChild(presenter.Content as ItemsPresenter) as IScrollInfo ??
                presenter;
    
            // Compute the center point of the container relative to the scrollInfo
            Size size = container.RenderSize;
            Point center = container.TransformToAncestor((Visual)scrollInfo).Transform(new Point(size.Width / 2, size.Height / 2));
            center.Y += scrollInfo.VerticalOffset;
            center.X += scrollInfo.HorizontalOffset;
    
            // Adjust for logical scrolling
            if (scrollInfo is StackPanel || scrollInfo is VirtualizingStackPanel)
            {
                double logicalCenter = itemsControl.ItemContainerGenerator.IndexFromContainer(container) + 0.5;
                Orientation orientation = scrollInfo is StackPanel ? ((StackPanel)scrollInfo).Orientation : ((VirtualizingStackPanel)scrollInfo).Orientation;
                if (orientation == Orientation.Horizontal)
                    center.X = logicalCenter;
                else
                    center.Y = logicalCenter;
            }
    
            // Scroll the center of the container to the center of the viewport
            if (scrollInfo.CanVerticallyScroll) scrollInfo.SetVerticalOffset(CenteringOffset(center.Y, scrollInfo.ViewportHeight, scrollInfo.ExtentHeight));
            if (scrollInfo.CanHorizontallyScroll) scrollInfo.SetHorizontalOffset(CenteringOffset(center.X, scrollInfo.ViewportWidth, scrollInfo.ExtentWidth));
        }
    
        private static double CenteringOffset(double center, double viewport, double extent)
        {
            return Math.Min(extent - viewport, Math.Max(0, center - viewport / 2));
        }
        private static DependencyObject FirstVisualChild(Visual visual)
        {
            if (visual == null) return null;
            if (VisualTreeHelper.GetChildrenCount(visual) == 0) return null;
            return VisualTreeHelper.GetChild(visual, 0);
        }
    

    这是我在 xaml.cs 或 DataObject 中滚动无代码的 TreeView 的完整解决方案。

    感谢向用户 AwkwardCoder 提出的行为理念

    如果有人有一些改进的小窍门,我喜欢听 ;-)

    【讨论】:

      【解决方案3】:

      我认为你不能。 DataTrigger 仅用于更改 WPF 级别的表示。标准方法是使用控件提供的事件作为事件。

      【讨论】:

      • 所以这是从 ViewModel 到 .xaml.cs 的方法吗?我想我可以在不向 ViewModel 添加代码的情况下处理这个问题......
      • 正如我在下面所说的,您可以使用 xaml 行为来做到这一点
      • 非常好,行为是一个很好的解决方案!明天用代码回答 =)
      【解决方案4】:

      TreeViewItem 类有一个 IsSelected 和一个重要的 Selected 事件,因此理论上您可以在 TreeViewItem 创建时为 Selected 事件设置和事件处理程序。

      希望这应该很明显,这在 MVVM secenario 中不起作用,因为您无法访问创建的 TreeViewItem 实例,在这种情况下,我希望使用 TreeView 控件的 Behavior 来执行此操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-22
        • 2015-09-15
        • 2014-11-14
        • 2018-06-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多