让我们看两个例子:
对于焦点,我们必须在代码隐藏中调用方法 UIelement.Focus()
,因此MVVM中的标准方法是创建* behaviour`:
public static class FocusedBehavior
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(FocusedBehavior), new UIPropertyMetadata(false, OnIsFocusedChanged));
private static void OnIsFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if((bool)e.NewValue)
(sender as UIElement).Focus();
}
}
然后对于每个控件,我们希望能够设置我们的焦点
<Button ... local:FocusedBehavior.IsFocused="{Binding SomeDependencyProperty}"/>
必须在ViewModel中为每个控件单独创建bool SomeDependencyProperty
。这样,ViewModel可以通过设置自己的属性值来改变View中的某些内容。
要设置模糊(see here),我们必须更改属性BlurEffect.Radius
。这可以像
<Window.Effect>
<BlurEffect Radius="{Binding SomeDependencyProperty}"/>
</Window.Effect>
再次必须在ViewModel中为每个案例创建int SomeProperty
。
ViewModel在View中是否还有方式更改内容?
我想知道能够使用最合适的所有可能性。要设置焦点,我们必须使用行为方法来设置模糊简单绑定。还有更多的可能性吗?
非常通用的解决方案是让ViewModel了解View,因此它可以调用方法并使用属性,例如处理命令,但这是个坏主意。对?虽然在这种情况下,View可以扩展本身,使用公共属性和方法来实现某些结果(例如,设置焦点或设置模糊)。
答案 0 :(得分:2)
您的问题似乎有点未经考虑......通过更改视图模型中的属性,我可以通过使用IValueConverter
s,{{1}来查看视图中发生的任何事情。 } s,附加属性等。例如,您不需要使用DataTrigger
或附加属性来聚焦UI元素。您可以使用视图模型中的普通DependencyProperty
属性和bool
这样的属性:
DataTrigger
所以,你似乎在问WPF中有什么可能,我认为这不是一个合理的范围(或主题)问题。要找到答案,最好通过MSDN上的Walkthrough: Getting Started with WPF页面阅读。
但是,我认为您实际上可能会问如何通过ViewModel更改View中的内容[特别是在使用MVVM时]。在这种情况下,我可以想到另一个使用过的元素:简陋的delegate
,它使我们能够在相关的视图模型之间传递值,或者在您的情况下,从视图模型传递到视图。
使用这种机制,我们可以从视图模型中间接[间接]调用视图中的UI方法,正如我之前所说的......我们可以做任何事情 - MVVM不会阻止我们使用WPF提供的任何东西。
顺便说一下,为什么在视图模型中使用<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding PropertyName}">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding
RelativeSource={RelativeSource Self}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
?您不应该在视图模型中声明任何声明,因为它们用于UI元素...在视图模型中,您可以实现DependencyProperty
接口并使用具有完全相同功能的普通旧CLR属性,但是复杂性较低。
更新&gt;&gt;&gt;
如上所述,INotifyPropertyChanged
是一个UI类,用于UI控件,例如DependencyProperty
。它们在视图模型中使用是完全过度的,因为如上所述,我们可以在那里使用普通的CLR属性。如果您查看MSDN上的DependencyProperty
Class页面,您将能够看到它有多少公共成员...为什么在您不使用时支付所有这些(在RAM中)< em>任何他们?
UserControl
接口不会添加任何超过INotifyPropertyChanged
的内容,而是提供相同的属性通知访问权限,但成本大大降低(没有数百个未使用的属性)。我可以告诉你说你所有的视图模型扩展了DependencyProperty
类,你误解了下面的着名错误:
的
DependencyObject
只能在Binding
DependencyProperty
上设置
我承认这是一个误导性的错误, 混淆了新的WPF用户。所以,我给你的建议是你在视图模型中实现普通的CLR类型属性,并且不扩展DependencyObject
类...你也可以删除你的UI相关的dll DependencyObject
s。此外,在使用CLR属性时,您需要正确实现INotifyPropertyChanged
interface,以便将它们“插入”WPF属性更改通知框架。
现在,您询问如何使用using
来将视图模型中的数据传递给视图...不幸的是,这是另一个完整的问题,而且我几乎没有时间在此题。因此,我不想再重复整个故事,而是建议您在Stack Overflow上阅读我对Passing parameters between viewmodels和How to call functions in a main view model from other view models?问题的答案,以获得解释和代码示例。
如果你没有留下进一步的评论来询问有关此事的更多信息,我会很感激,因为这个答案现在已经足够长了。如果您还有其他问题,请提出新问题并提供尽可能多的代码/信息。