在呈现/实例化View时通知ViewModel

时间:2015-04-23 11:55:53

标签: c# wpf mvvm view viewmodel

我有一个自定义用户控件(ChartControl),我在我的WPF应用程序(MainApp)中使用,我按如下方式呈现:

<ContentControl Grid.Row="1" Content="{Binding ChartControl, Mode=OneWay}" />

启动MainApp后,将按给定顺序执行以下操作:

MainApp视图 MainApp ViewModel ChartControl ViewModel ChartControl视图

我在ChartControl ViewModel的构造函数中实例化MainApp ViewModel。问题是在实例化ChartControl ViewModel后,我还需要从ChartControl内调用MainApp的方法。

我遇到的问题是,在将方法作为其viewmodel的一部分调用之前,我需要呈现ChartControl视图(执行其InitializeComponent)。

我认为一个解决方案是在完全实例化和设置时从视图中通知视图模型。这是一个可行的解决方案,如果是,我该怎么做?

总之,我需要在调用匹配的viewmodel的方法之前完全设置视图。我遇到的问题是,在这种情况下,视图模型首先被实例化,然后才会呈现视图。

有什么想法吗?

由于

4 个答案:

答案 0 :(得分:5)

您可以使用Interactivity触发器在任何UI事件上触发VM上的Command

您可以像下面一样收听UserControl的Loaded事件,并将其绑定到VM上的Command:

<UserControl x:Class="Test.TestView.MyUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        x:Name="myControl" >

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding ElementName=myControl, Path=OnLoadedCommand}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

确保您的VM中有Command

public ICommand OnLoadedCommand { get; private set; }

public MyUserControl()
{
    OnLoadedCommand = new DelegateCommand(OnLoaded);
}

public void OnLoaded()
{
}

答案 1 :(得分:5)

连接Loaded事件的另一种方法,基本上呈现与nit的答案相同的结果,只是在视图的构造函数中引用您的viewmodel并添加一个事件处理程序,该处理程序又调用您需要的任何方法打电话,像这样:

public MyControl()
{
   InitializeComponent();

   this.Loaded += (s, e) => { ((MyViewModel)DataContext).MyInitializer(); };
}

如果您发现语法令人困惑,可能需要阅读Anonymous methodsSubscribing to event handlers (using anonymous methods)

答案 2 :(得分:2)

我正在使用像Hogler这样的类似解决方案,只有反射(懒惰耦合解决方案)。我不想引用我的ViewModel的特定类型(因为通用性,可互换性等)。

public MyControl()
{
   InitializeComponent();
   Loaded += MyControl_Loaded;
}

private void MyControl_Loaded(object sender, RoutedEventArgs e)
{   
  (DataContext.GetType().GetProperty("LoadedCommand")?.
    GetValue(DataContext) as ICommand)?.
    Execute(null);
}

ViewModel可以(不必)包含所需的命令,如属性(在本例中为LoadedCommand)。没什么。

答案 3 :(得分:1)

在MVVM世界中,我发现在创建可视项目并将其放到视图上时(在这种情况下添加到列表中),在加载的事件被触发之前,该项目不会在可视树中。

我的视图模型包含XAML视图将显示的可观察集合中的项目列表。

ObservableCollection<MyControl> Items;

我会在列表中添加一个项目,但是当我执行一项要求它在可视化树中并执行可视树递归的操作时,这不可能立即发生。相反,我必须编写类似这样的代码:

var newItem = new MyControl();

newItem.Loaded += NewItemLoaded;

Items.Add(new MyControl());

然后事件处理程序将取消挂钩并执行操作 - 此时根据需要位于可视化树中:

private void NewItemLoaded(object sender, RoutedEventArgs e)
{
    var item = sender as MyControl;
    item.Loaded -= NewItemLoaded;

    // now this item is in the visual tree, go ahead and do stuff ...
}