如何通过ViewModel在View中更改内容

时间:2014-06-04 10:01:59

标签: c# wpf mvvm

让我们看两个例子:

设置焦点

对于焦点,我们必须在代码隐藏中调用方法 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可以扩展本身,使用公共属性和方法来实现某些结果(例如,设置焦点或设​​置模糊)。

1 个答案:

答案 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 viewmodelsHow to call functions in a main view model from other view models?问题的答案,以获得解释和代码示例。

如果你没有留下进一步的评论来询问有关此事的更多信息,我会很感激,因为这个答案现在已经足够长了。如果您还有其他问题,请提出新问题并提供尽可能多的代码/信息。