如何从视图模型访问不可绑定的视图属性?
How to access non-bindable view properties from the view model?
我正在使用 Telerik WPF RadGanttView
控件来显示一堆数据。由于数据可以是任意奇怪的 - 瞬时事件,或者持续几天,或者它们之间有一周 - 不可能设置保证有用的 PixelLength
(即比例因子)。有人要求我可以使用滑块更改此比例因子。不幸的是,仅使用滑块更改比例因子存在可用性问题,我需要通过手动调整视图滚动的位置来解决此问题。我不知道具体如何。
概述我正在修复的可用性问题:视图通过提供 "viewport" 来工作,该 "viewport" 位于整个 "extent" 数据集的 "offset" 处。 (从 Telerik API 中提取的术语。这些似乎只是表示可滚动视图下方 canvas 中的像素。)当比例因子从 100% 变为 200%(对应于将PixelLength
),发生的情况是 extent 的宽度加倍,但水平 offset
保持不变。结果是放大后,您很可能会看到与之前完全不同的数据,因为之前的事件在右侧的视口中 "pulled out"。
我打算解决这个问题的方法是:在放大之前抓住 offset/viewport/extent 等,放大,然后做一些我还没有弄清楚的数学和新的 offset/viewport/extent。问题是:描述滚动内容的 RadGanttView
的属性是 而不是 DependencyProperty
,我不能简单地将它们绑定到 [=18= 上的属性]. (事实上 ,它们甚至无法在 XAML 中访问,RadGanttView
明确实现 IScrollingInfo
。)
所以,我的问题是:我如何在我的 ViewModel
或其他任何地方响应 ViewModel
的比例因子变化,访问相应 View
,那个不能数据绑定?我尝试的每一次搜索都告诉我,从视图模型访问视图是 "not MVVM",但由于 Telerik 是第三方库,我无法真正重构他们这边的工作方式。
我的代码填空大纲:
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
<UserControl ... d:DataContext="{d:DesignInstance my:FooViewModel}">
<telerik:RadGanttView x:Name="Gantt">
<!-- ... -->
</telerik:RadGanttView>
</UserControl>
我调查过的事情:
- 在
FooView
代码隐藏中制作一堆 DependencyProperty
包装器,只访问 RadGanttView
中的相应属性。这似乎都是对系统的可怕滥用——也就是说,没有 DependencyObject
支持的依赖项 属性 似乎没有意义。而且它显然行不通 - 在 WPF 中,视图似乎将 "push" 数据放入视图模型中,而且我仍然无法实际获取当前值,因为包装器属性的值永远不会更新。
- 呃,
Command
s,也许吧?我是 WPF 的新手,我完全不知道它们是如何工作的,只是一个模糊的印象,它们可能是视图模型与视图对话的一种松散耦合方式。
- 附加属性?自定义绑定?远远高于我的薪水等级,如果他们有帮助我不知道自己如何。看起来他们可以完成 "dirty" 将控件绑定到视图模型 属性 的解决方案。因为 属性 的类型是
IScrollingInfo
,而不是整个视图,所以我可以接受。
附加行为可能会解决您的问题。它们基本上是带有回调的附加属性。
查看我的回答。只需注册到 Changed
事件(或您的控件实际调用它的任何内容),而不是 KeyDown
事件,然后将从 Changed 事件中获得的值分配给附加的 属性,并且你有两种方式绑定到一个不可绑定的 属性
我正在使用 Telerik WPF RadGanttView
控件来显示一堆数据。由于数据可以是任意奇怪的 - 瞬时事件,或者持续几天,或者它们之间有一周 - 不可能设置保证有用的 PixelLength
(即比例因子)。有人要求我可以使用滑块更改此比例因子。不幸的是,仅使用滑块更改比例因子存在可用性问题,我需要通过手动调整视图滚动的位置来解决此问题。我不知道具体如何。
概述我正在修复的可用性问题:视图通过提供 "viewport" 来工作,该 "viewport" 位于整个 "extent" 数据集的 "offset" 处。 (从 Telerik API 中提取的术语。这些似乎只是表示可滚动视图下方 canvas 中的像素。)当比例因子从 100% 变为 200%(对应于将PixelLength
),发生的情况是 extent 的宽度加倍,但水平 offset
保持不变。结果是放大后,您很可能会看到与之前完全不同的数据,因为之前的事件在右侧的视口中 "pulled out"。
我打算解决这个问题的方法是:在放大之前抓住 offset/viewport/extent 等,放大,然后做一些我还没有弄清楚的数学和新的 offset/viewport/extent。问题是:描述滚动内容的 RadGanttView
的属性是 而不是 DependencyProperty
,我不能简单地将它们绑定到 [=18= 上的属性]. (事实上 ,它们甚至无法在 XAML 中访问,RadGanttView
明确实现 IScrollingInfo
。)
所以,我的问题是:我如何在我的 ViewModel
或其他任何地方响应 ViewModel
的比例因子变化,访问相应 View
,那个不能数据绑定?我尝试的每一次搜索都告诉我,从视图模型访问视图是 "not MVVM",但由于 Telerik 是第三方库,我无法真正重构他们这边的工作方式。
我的代码填空大纲:
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
<UserControl ... d:DataContext="{d:DesignInstance my:FooViewModel}">
<telerik:RadGanttView x:Name="Gantt">
<!-- ... -->
</telerik:RadGanttView>
</UserControl>
我调查过的事情:
- 在
FooView
代码隐藏中制作一堆DependencyProperty
包装器,只访问RadGanttView
中的相应属性。这似乎都是对系统的可怕滥用——也就是说,没有DependencyObject
支持的依赖项 属性 似乎没有意义。而且它显然行不通 - 在 WPF 中,视图似乎将 "push" 数据放入视图模型中,而且我仍然无法实际获取当前值,因为包装器属性的值永远不会更新。 - 呃,
Command
s,也许吧?我是 WPF 的新手,我完全不知道它们是如何工作的,只是一个模糊的印象,它们可能是视图模型与视图对话的一种松散耦合方式。 - 附加属性?自定义绑定?远远高于我的薪水等级,如果他们有帮助我不知道自己如何。看起来他们可以完成 "dirty" 将控件绑定到视图模型 属性 的解决方案。因为 属性 的类型是
IScrollingInfo
,而不是整个视图,所以我可以接受。
附加行为可能会解决您的问题。它们基本上是带有回调的附加属性。
查看我的回答Changed
事件(或您的控件实际调用它的任何内容),而不是 KeyDown
事件,然后将从 Changed 事件中获得的值分配给附加的 属性,并且你有两种方式绑定到一个不可绑定的 属性