简体   繁体   English

如何从视图模型访问不可绑定的视图属性?

[英]How to access non-bindable view properties from the view model?

I'm using the Telerik WPF RadGanttView control to display a bunch of data. 我正在使用Telerik WPF RadGanttView控件来显示大量数据。 Since the data can be arbitrarily weird - events that are instantaneous, or that last days, or have a week between them - it's not possible to set a PixelLength (ie a scale factor) that's guaranteed to be useful. 由于数据可能是任意奇怪的-瞬时事件,持续时间或最后几天或事件之间有一周的时间-不可能设置保证有用的PixelLength (即比例因子)。 I've been asked to make it possible to change this scale factor with a slider. 我被要求使用滑块来更改此比例因子。 Unfortunately, just changing the scale factor with the slider has a usability issue, which I need to fix by manually adjusting where the view is scrolled. 不幸的是,仅使用滑块更改比例因子会带来可用性问题,我需要通过手动调整视图的滚动位置来解决。 I'm at a loss as to how exactly. 我不知道该怎么做。

To outline the usability problem I'm fixing: the view works by providing a "viewport", located at an "offset", over the whole "extent" of the data set. 为了概述我要解决的可用性问题:该视图通过在数据集的整个“范围”内的“偏移”处提供一个“视口”来工作。 (Terms lifted from the Telerik API . These seem to simply represent pixels in the canvas underlying the scrollable view.) When the scale factor goes from, say, 100% to 200% (which corresponds to halving the PixelLength ), what happens is that the width of the extent is doubled, but the horizontal offset remains the same. (从Telerik API提起的术语。这些似乎只是表示可滚动视图下面的画布中的像素。)当比例因子从100%变为200%(相当于将PixelLength减半)时,会发生什么事情? 程度的宽度加倍,但水平offset保持相同。 The consequence is that after zooming in, it's quite likely you'll see entirely different data than before, since the events that were there before got "pulled out" of the viewport to the right. 结果是放大后,很有可能您会看到与以前完全不同的数据,因为之前存在的事件被“拉出”了右侧的视口。

The way I intend to fix this is: grab the offset/viewport/extent etc before zooming in, zoom, then do some maths I haven't figured out yet with that and the new offset/viewport/extent. 我打算解决的方法是:在放大,缩放之前获取偏移量/视口/范围等,然后进行一些我还没有弄清楚的数学运算以及新的偏移量/视口/范围。 The problem is: the properties of RadGanttView that describe the scrolling stuff are not DependencyProperty s, and I cannot simply bind them to properties on my ViewModel . 问题是:描述滚动内容的RadGanttView的属性不是 DependencyProperty ,并且我不能简单地将它们绑定到ViewModel属性。 (In fact, they're not even accessible in XAML to begin with, RadGanttView implements IScrollingInfo explicitly.) (事实上,他们甚至还没有在XAML访问开始, RadGanttView实现IScrollingInfo明确。)

So, my question is: how do I, in my ViewModel , or wherever else in reaction to the ViewModel 's scale factor changing, access properties of a control in the corresponding View , that cannot be data-bound? 因此,我的问题是:如何在我的ViewModel ,或者响应ViewModel的缩放因子变化的其他地方,如何访问相应View控件的属性,而该属性不能是数据绑定的? Every search I tried tells me that accessing the view from the viewmodel is "not MVVM", but since Telerik is a third-party library, I can't really refactor how this works on their side. 我尝试进行的每一次搜索都告诉我,从viewmodel访问视图是“不是MVVM”,但是由于Telerik是第三方库,因此我无法真正重构它在它们方面的工作方式。

A fill-in-the-blanks outline of my code: 我的代码的空白处概述:

FooViewModel.cs FooViewModel.cs

class FooViewModel 
{

    // A slider in the view pushes its value into this property
    double ScaleFactor 
    {
        get { /*...*/ }
        set
        {
            PixelLength = GetNewPixelLength(value);
            // ...
        }
    }

    // The RadGanttView pulls its scale from this property
    double PixelLength
    {
        get { ... }
        set
        {
            // How do I get these values?
            var oldOffset = ???;
            var oldExtent - ???;

            // Trigger the actual change in the view.
            PropertyChanged("PixelLength", ...);

            var newExtent = ???;
            ???.HorizontalOffset =  GetNewOffset(...);
        }
    }
}

FooView.xaml FooView.xaml

<UserControl ... d:DataContext="{d:DesignInstance my:FooViewModel}">
    <telerik:RadGanttView x:Name="Gantt">
        <!-- ... -->
    </telerik:RadGanttView>
</UserControl>

Things I've looked into: 我调查过的事情:

  • Making a bunch of DependencyProperty wrappers in the FooView code-behind that just access corresponding properties in the RadGanttView . 制作了一堆DependencyProperty在包装FooView刚刚访问相应的属性代码隐藏RadGanttView This seems like it both is a horrible abuse of the system - ie it doesn't seem to make sense to have a dependency property not backed by a DependencyObject . 似乎两者都是对系统的可怕滥用—即,没有由DependencyObject支持的依赖项属性似乎没有任何意义。 And also that it plain wouldn't work - in WPF, the view seems to "push" data into the view model, and I'd still have no way to actually get the current values, since the values of the wrapper properties would never get updated. 而且,这显然是行不通的-在WPF中,视图似乎将数据“推入”视图模型,并且我仍然没有办法真正获取当前值,因为包装器属性的值永远不会得到更新。
  • Uh, Command s, maybe? 嗯,也许是Command I'm fairly new at WPF, I have no clue how those work at all, merely a vague impression that they might be a loosely coupled way for the view model to talk to the view. 我是WPF的新手,我根本不知道它们是如何工作的,只是模糊的印象,它们可能是视图模型与视图对话的松散耦合方式。
  • Attached properties? 附加属性? Custom bindings? 自定义绑定? Way above my pay grade, if they help I don't know how myself. 如果他们帮助的话,我的薪水远高于我的薪水水平,我自己也不知道。 It seems like they could accomplish the "dirty" solution of just binding a control to a view model property. 看来他们可以完成仅将控件绑定到视图模型属性的“肮脏”解决方案。 Since the type of that property would be IScrollingInfo , not the whole view, I could live with that. 由于该属性的类型将是IScrollingInfo ,而不是整个视图,因此我可以接受。

Attached Behaviors may solve your issue. 附加行为可能会解决您的问题。 They are basically Attached Properties with a callback. 它们基本上是带有回调的附加属性。

Check out my answer here . 在这里查看我的答案。 Just instead of KeyDown event, you register to the Changed event (or whatever your control is actually calling it) and then assign the value you get from the Changed event to your Attached Property, and you have two way binding on a non-bindable property 仅注册Changed事件(或控件实际调用的任何事件),而不是KeyDown事件,然后将您从Changed事件获得的值分配给Attached Property,并且在非绑定属性上有两种绑定方式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM