【发布时间】:2016-09-16 01:45:34
【问题描述】:
我有一个带有 ViewModel 的 WPF UserControl:
<MyUserControl ...>
<Grid Name="UxRootContainer">
<Grid.DataContext>
<MyViewModel/>
</Grid.DataContext>
</Grid>
</MyUserControl>
这个 UserControl 有一个 DependencyProperty,它必须被传播到 ViewModel:
public static readonly DependencyProperty DurationProperty =
DependencyProperty.Register( "Duration", typeof(TimeSpan),
typeof(MyUserControl), new FrameworkPropertyMetadata(TimeSpan.FromHour(1), OnDurationChanged ));
public TimeSpan Duration
{
get { return (TimeSpan)GetValue(DurationProperty); }
set { SetValue(DurationProperty, value); }
}
private static void OnDurationChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
MyUserControl control = source as MyUserControl;
TimeSpan duration = (TimeSpan)e.NewValue;
control.UxRootContainer.SetDuration(duration);
}
这工作正常,除了我们不会在OnDurationChanged 事件中收到默认值。
我知道我可以自己在构造函数中调用此方法,将默认持续时间放入一个常量中,但是:
- 我必须为每个 DependencyProperty 创建一个常量
- 即使最后我不使用默认值,我也必须调用它
关于如何将默认值传播到 ViewModel 的任何好的建议,前提是默认值是最后使用的那个(不是其他值集)。
【问题讨论】:
-
这不是真正的 MVVM。在视图中创建 ViewModel 通常是个坏主意(对于主窗口可能没问题)。关键是
UserControl通常是ViewModel的数据模板(这意味着您将在某处拥有ViewModel,但您的控件不能用作数据模板,因为它明确设置了DataContext)。之后你应该做相反的事情:View从ViewModel获取值(无论是默认值还是新值)。这可以在Loaded事件中完成(您将 100% 获得此事件)。 -
@Sinatr 这有点离题,但我很抱歉,但我不同意,MVVM 可以先查看或先查看模型。对于视图,我们使用 Prism ViewModelLocator 来获取 ViewModel。在这种情况下,这并不是真正的“视图”,而是真正的用户控件,可以在应用程序的许多不同上下文中使用。如果您的 TextBlock 必须找到自己必须显示的字段,您不觉得这很奇怪吗? ;)
-
@Sinatr 我后面有一个“ViewModel”,只是为了拥有我的内部可绑定属性。我同意这个名字可能不是最好的,但它包含与真正的 ViewModel 相同的逻辑(命令,INotifyPropertyChange 实现,...)
-
“你不觉得如果你的 TextBlock 必须自己找到它必须显示的字段会很奇怪吗” - 不。绑定已经使 View 元素不知道任何事情。
TextBlock不知道最后会显示什么。如果您创建 2 个 ViewModel 实例,它们可能具有不同的值以显示相同的视图。因此,不要从视图中获得价值。 View 应该从 ViewModel 中获取价值。 -
@Sinatr 不。就像我说的,这个 UserControl 将在很多不同的 View 中使用,这些 View 已经有他们的 ViewModel。更具体地说,我的 UserControl 只有一个 Point 集合和一个持续时间(即要显示的点数)。它不知道这些点来自哪里,这完全取决于将使用哪个视图。与 TextBlock 相同。
标签: c# wpf mvvm user-controls