当 View 为 rendered/instantiated 时通知 ViewModel
Notify ViewModel when View is rendered/instantiated
我有一个自定义用户控件 (ChartControl
),我在我的 WPF 应用程序 (MainApp
) 中使用它,我将其呈现如下:
<ContentControl Grid.Row="1" Content="{Binding ChartControl, Mode=OneWay}" />
启动 MainApp
后,将按给定顺序执行以下操作:
主应用视图
主应用视图模型
图表控件视图模型
图表控件视图
我从 MainApp
ViewModel 的构造函数中实例化了 ChartControl
ViewModel。问题是在实例化 ChartControl
ViewModel 之后,我还需要从 MainApp
中调用 ChartControl
的方法。
我遇到的问题是,在调用该方法作为其视图模型的一部分之前,我需要呈现 ChartControl
视图(执行其 InitializeComponent
)。
我认为一种解决方案是在完全实例化和设置时从视图通知视图模型。这是一个可行的解决方案吗?如果是,我该怎么做?
总而言之,我需要在调用匹配视图模型的方法之前完全设置视图。我遇到的问题是,在这种情况下,首先实例化视图模型,然后才呈现视图。
有什么想法吗?
谢谢
您可以使用交互触发器在任何 UI 事件发生时在您的 VM 上触发命令
您可以像下面这样监听 UserControl 的 Loaded 事件并将其绑定到 VM 上的命令:
<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 中有命令
public ICommand OnLoadedCommand { get; private set; }
public MyUserControl()
{
OnLoadedCommand = new DelegateCommand(OnLoaded);
}
public void OnLoaded()
{
}
连接 Loaded 事件的另一种方法,基本上呈现与 nit 的回答相同的结果,只是在视图的构造函数中引用您的视图模型并添加一个事件处理程序,该事件处理程序依次调用您需要调用的任何方法,像这样:
public MyControl()
{
InitializeComponent();
this.Loaded += (s, e) => { ((MyViewModel)DataContext).MyInitializer(); };
}
如果您发现语法令人困惑,您可能需要阅读 Anonymous methods and Subscribing to event handlers (using anonymous methods)。
我正在使用类似于 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)。仅此而已。
在 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 ...
}
我有一个自定义用户控件 (ChartControl
),我在我的 WPF 应用程序 (MainApp
) 中使用它,我将其呈现如下:
<ContentControl Grid.Row="1" Content="{Binding ChartControl, Mode=OneWay}" />
启动 MainApp
后,将按给定顺序执行以下操作:
主应用视图 主应用视图模型 图表控件视图模型 图表控件视图
我从 MainApp
ViewModel 的构造函数中实例化了 ChartControl
ViewModel。问题是在实例化 ChartControl
ViewModel 之后,我还需要从 MainApp
中调用 ChartControl
的方法。
我遇到的问题是,在调用该方法作为其视图模型的一部分之前,我需要呈现 ChartControl
视图(执行其 InitializeComponent
)。
我认为一种解决方案是在完全实例化和设置时从视图通知视图模型。这是一个可行的解决方案吗?如果是,我该怎么做?
总而言之,我需要在调用匹配视图模型的方法之前完全设置视图。我遇到的问题是,在这种情况下,首先实例化视图模型,然后才呈现视图。
有什么想法吗?
谢谢
您可以使用交互触发器在任何 UI 事件发生时在您的 VM 上触发命令
您可以像下面这样监听 UserControl 的 Loaded 事件并将其绑定到 VM 上的命令:
<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 中有命令
public ICommand OnLoadedCommand { get; private set; }
public MyUserControl()
{
OnLoadedCommand = new DelegateCommand(OnLoaded);
}
public void OnLoaded()
{
}
连接 Loaded 事件的另一种方法,基本上呈现与 nit 的回答相同的结果,只是在视图的构造函数中引用您的视图模型并添加一个事件处理程序,该事件处理程序依次调用您需要调用的任何方法,像这样:
public MyControl()
{
InitializeComponent();
this.Loaded += (s, e) => { ((MyViewModel)DataContext).MyInitializer(); };
}
如果您发现语法令人困惑,您可能需要阅读 Anonymous methods and Subscribing to event handlers (using anonymous methods)。
我正在使用类似于 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)。仅此而已。
在 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 ...
}