绑定到 ScrollViewer 的 ViewportWidth 和 ViewportHeight

发布于 2024-09-09 12:34:12 字数 518 浏览 9 评论 0原文

我正在构建的 WPF 应用程序中使用模型-视图-视图模型架构,并且我希望特定的视图模型能够真正对视图的大小做出反应(我知道,这不是 MVVM 方法的正常用例) 。

本质上,我有一个 ScrollViewer 对象,我希望视图模型观察滚动查看器的宽度和高度,然后能够根据宽度和高度相应地执行操作。

我想做这样的事情:

<ScrollViewer ViewportWidth="{Binding Path=MyViewportWidth, Mode=OneWayToSource}" ViewportHeight="{Binding Path=MyViewportHeight, Mode=OneWayToSource}" />

但是当然这是不可能做到的,因为“ViewportWidth”和“ViewportHeight”不能“绑定到”(也称为绑定目标),因为它们是只读依赖属性(即使我根本没有在此绑定中给他们写信,因为它是 OneWayToSource)。

有人知道能够做这样的事情的好方法吗?

I am using the Model-View-ViewModel architecture in a WPF application I am building, and I would like a specific ViewModel to actually be reactive to the size of the view (not a normal use-case of the MVVM approach, I know).

Essentially, I have a ScrollViewer object and I want the viewmodel to observe the width and height of the scrollviewer and then be able to do things accordingly depending on what that width and height are.

I'd like to do something like this:

<ScrollViewer ViewportWidth="{Binding Path=MyViewportWidth, Mode=OneWayToSource}" ViewportHeight="{Binding Path=MyViewportHeight, Mode=OneWayToSource}" />

But of course this is impossible to do because "ViewportWidth" and "ViewportHeight" cannot be "bound to" (a.k.a. act as binding targets) because they are read-only dependency properties (even though I am not writing to them at all in this binding since it is OneWayToSource).

Anyone know of a good method to be able to do something like this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

眸中客 2024-09-16 12:34:16

您可以尝试运行 OnLoaded 或 OnResizeChanged 来更新视图模型

private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
   ScrollViewer sv = sender as ScrollViewer;
   ViewModel vm = sv.DataContext as ViewModel;

   vm.ScrollViewerHeight = sv.ViewportHeight;
   vm.ScrollViewerWidth = sv.ViewportWidth;
}

You could try running something OnLoaded or OnResizeChanged that updates the viewmodel

private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
   ScrollViewer sv = sender as ScrollViewer;
   ViewModel vm = sv.DataContext as ViewModel;

   vm.ScrollViewerHeight = sv.ViewportHeight;
   vm.ScrollViewerWidth = sv.ViewportWidth;
}
别挽留 2024-09-16 12:34:16

好吧,这是一个非常的老问题,但我想我应该为后代分享,因为我自己已经解决了这个问题。我发现的最佳解决方案是创建一个从 ScrollView 类派生的用户控件,并实现您想要的属性 - 当然,这些属性链接到基类的不可绑定属性。

您可以使用 OnPropertyChanged 函数来监视这些属性并使值保持同步。

这是我的自定义用户控件 DynamicScrollViewer 的完整代码隐藏。请注意,我有四个可绑定依赖项属性,称为 DynamicHorizo​​ntalOffset、DynamicVerticalOffset、DynamicViewportWidth 和 DynamicViewportHeight。

这两个偏移属性允许对偏移进行读写控制,而视口属性本质上是只读的。

在创建复杂的动画编辑器控件时,我必须使用此类,其中各种组件(左侧的标签、中间的节点、顶部的时间轴)需要同步滚动,但仅限于有限的方面,并且全部绑定到公共外部滚动条。想象一下锁定电子表格中的一部分行,您就明白了。

using System.Windows;
using System.Windows.Controls;

namespace CustomControls
{
    public partial class DynamicScrollViewer : ScrollViewer
    {
        public DynamicScrollViewer()
        {
            InitializeComponent();
        }

        public double DynamicHorizontalOffset
        {
            get { return (double)GetValue(DynamicHorizontalOffsetProperty); }
            set { SetValue(DynamicHorizontalOffsetProperty, value); }
        }

        public static readonly DependencyProperty DynamicHorizontalOffsetProperty =
            DependencyProperty.Register("DynamicHorizontalOffset", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicVerticalOffset
        {
            get { return (double)GetValue(DynamicVerticalOffsetProperty); }
            set { SetValue(DynamicVerticalOffsetProperty, value); }
        }

        public static readonly DependencyProperty DynamicVerticalOffsetProperty =
            DependencyProperty.Register("DynamicVerticalOffset", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicViewportWidth
        {
            get { return (double)GetValue(DynamicViewportWidthProperty); }
            set { SetValue(DynamicViewportWidthProperty, value); }
        }

        public static readonly DependencyProperty DynamicViewportWidthProperty =
            DependencyProperty.Register("DynamicViewportWidth", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicViewportHeight
        {
            get { return (double)GetValue(DynamicViewportHeightProperty); }
            set { SetValue(DynamicViewportHeightProperty, value); }
        }

        public static readonly DependencyProperty DynamicViewportHeightProperty =
            DependencyProperty.Register("DynamicViewportHeight", typeof(double), typeof(DynamicScrollViewer));

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == DynamicVerticalOffsetProperty)
            {
                if (ScrollInfo != null)
                    ScrollInfo.SetVerticalOffset(DynamicVerticalOffset);
            }
            else if (e.Property == DynamicHorizontalOffsetProperty)
            {
                if (ScrollInfo != null)
                    ScrollInfo.SetHorizontalOffset(DynamicHorizontalOffset);
            }
            else if (e.Property == HorizontalOffsetProperty)
            {
                DynamicHorizontalOffset = (double)e.NewValue;
            }
            else if (e.Property == VerticalOffsetProperty)
            {
                DynamicVerticalOffset = (double)e.NewValue;
            }
            else if (e.Property == ViewportWidthProperty)
            {
                DynamicViewportWidth = (double)e.NewValue;
            }
            else if (e.Property == ViewportHeightProperty)
            {
                DynamicViewportHeight = (double)e.NewValue;
            }
        }
    }
}

Ok, this is a really old question, but I thought I'd share for posterity, since I've solved this one myself. The best solution I've found is to create a user control that derives from the ScrollView class and implements the properties you want - which are of course linked to the non-bindable properties of the base class.

You can use the OnPropertyChanged function to monitor those properties and keep the values in sync.

Here's the full code-behind of my custom usercontrol called DynamicScrollViewer. Notice that I have four bindable dependency properties called DynamicHorizontalOffset, DynamicVerticalOffset, DynamicViewportWidth, and DynamicViewportHeight.

The two offset properties allow both read and write control of the offset, while the viewport properties are essentially read-only.

I had to use this class when creating a complex animation editor control in which various components (labels at the left, nodes in the middle, timeline at top) needed to scroll synchronously, but only in limited aspects, and were all bound to common external scrollbars. Think of locking a section of rows in spreadsheet, and you get the idea.

using System.Windows;
using System.Windows.Controls;

namespace CustomControls
{
    public partial class DynamicScrollViewer : ScrollViewer
    {
        public DynamicScrollViewer()
        {
            InitializeComponent();
        }

        public double DynamicHorizontalOffset
        {
            get { return (double)GetValue(DynamicHorizontalOffsetProperty); }
            set { SetValue(DynamicHorizontalOffsetProperty, value); }
        }

        public static readonly DependencyProperty DynamicHorizontalOffsetProperty =
            DependencyProperty.Register("DynamicHorizontalOffset", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicVerticalOffset
        {
            get { return (double)GetValue(DynamicVerticalOffsetProperty); }
            set { SetValue(DynamicVerticalOffsetProperty, value); }
        }

        public static readonly DependencyProperty DynamicVerticalOffsetProperty =
            DependencyProperty.Register("DynamicVerticalOffset", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicViewportWidth
        {
            get { return (double)GetValue(DynamicViewportWidthProperty); }
            set { SetValue(DynamicViewportWidthProperty, value); }
        }

        public static readonly DependencyProperty DynamicViewportWidthProperty =
            DependencyProperty.Register("DynamicViewportWidth", typeof(double), typeof(DynamicScrollViewer));

        public double DynamicViewportHeight
        {
            get { return (double)GetValue(DynamicViewportHeightProperty); }
            set { SetValue(DynamicViewportHeightProperty, value); }
        }

        public static readonly DependencyProperty DynamicViewportHeightProperty =
            DependencyProperty.Register("DynamicViewportHeight", typeof(double), typeof(DynamicScrollViewer));

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == DynamicVerticalOffsetProperty)
            {
                if (ScrollInfo != null)
                    ScrollInfo.SetVerticalOffset(DynamicVerticalOffset);
            }
            else if (e.Property == DynamicHorizontalOffsetProperty)
            {
                if (ScrollInfo != null)
                    ScrollInfo.SetHorizontalOffset(DynamicHorizontalOffset);
            }
            else if (e.Property == HorizontalOffsetProperty)
            {
                DynamicHorizontalOffset = (double)e.NewValue;
            }
            else if (e.Property == VerticalOffsetProperty)
            {
                DynamicVerticalOffset = (double)e.NewValue;
            }
            else if (e.Property == ViewportWidthProperty)
            {
                DynamicViewportWidth = (double)e.NewValue;
            }
            else if (e.Property == ViewportHeightProperty)
            {
                DynamicViewportHeight = (double)e.NewValue;
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文