ViewModel可以通过ResourceDictionary URI保存View的间接引用吗?

时间:2012-12-03 07:15:02

标签: wpf mvvm inversion-of-control

WPF和MVVM就像身体和灵魂一样。 ViewModel忽略它可能连接的View(反之亦然)是有道理的。

但是在ViewModel中保持对View资源字典的引用甚至是一种罪过。那会破坏目的吗?

e.g。如果VM可以通过资源字典保存视图引用,则下面的代码用于POC目的。 ViewModel可以动态更改此资源字典(基于某些输入参数)。

MyViewModel.cs

   public interface IViewInjectingViewModel
   {
      void Initialize();
      URI ViewResourceDictionary { get; }
   }

   public class MyViewModel : IViewInjectingViewModel
   {
       private URI _viewResourceDictionary;
       public void Initialize()
       {
          _viewResourceDictionary = new URI("pack://application:,,,/MyApplication;component/Resources/MyApplicationViews.xaml");
        }

        public URI ViewResourceDictionary 
        {
           get
           {
              return _viewResourceDictionary;
           }
        }
   }

MyApplicationViews.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate DataType="{x:Type local:MyViewModel}">
    <StackPanel>
        <TextBlock 
        Text="Portfolios" FontFamily="Verdana" 
        FontSize="16" FontWeight="Bold" Margin="6,7,6,4"/>
        <ListBox 
        Margin="2,1" SelectionMode="Single" 
        ItemsSource="{Binding AvailableTraders}"
        SelectedItem="{Binding SelectedTrader}" DisplayMemberPath="Name">
        <!-- ... -->
        </ListBox>
    </StackPanel>
    </DataTemplate>
</ResourceDictionary>

MainWindow.xaml

<Window ...>
     <ContentControl 
    DataContext="{Binding myViewModel}"
    local:MyBehaviors.InjectView="true"/>
</Window>

CommonBehaviors:

public static class MyBehaviors
{
    public static readonly DependencyProperty InjectViewProperty 
        = DependencyProperty.RegisterAttached(..);

    //attached getters and setters...

    private static void OnInjectViewPropertyChanged(..)
    {
        var host = o as ContentControl;
        if ((bool)e.NewValue)
        {
            host.DataContextChanged
                += (o1, e1)  =>
                {
                    var viewInjectingVM = host.DataContext as IViewInjectingViewModel;
                    if (viewInjectingVM != null)
                    {
                        host.Resources.MergedDictionaries.Clear();
                        host.Resources.MergedDictionaries.Add( 
                            new ResourceDictionary() {    
                                Source = viewInjectingVM.ViewResourceDictionary 
                            });

                        host.Content = viewInjectingVM;
                    }
                };
        }
    }
}

1 个答案:

答案 0 :(得分:0)

好的,我会开枪。我觉得这没关系。如果您认为视图模型是表示层的一部分,那么让视图模型更改视图的资源字典以响应某些操作就在MVVM范例内。

基本上,您正在更改视图的演示文稿以响应某些操作,并且视图模型具有此职责。因此,在此上下文中更新资源字典在MVVM模式中似乎是有效的。