mvvm 从加载的视图模型交叉执行方法
mvvm Cross execute methods from a loaded viewmodel
如何在加载的视图模型中执行方法?
我的结构;
MainView(TabControl) - MainViewModel
View1(Tab1) - ViewModel1
View2(Tab2) - ViewModel2
View3(Tab3) - ViewModel3
在每个 ViewModel 中都有一个 ReloadData() 方法,它从我的数据库中加载一些数据。他们已经像这样在构造函数中被解雇了;
public ViewModel1()
{
ReloadData();
}
private async void ReloadData(){ }
导航到 MainViewModel 时,它将直接(在 ViewAppeared-Method 中)导航到选项卡;
this._navigationService.Navigate<ViewModel1>();
this._navigationService.Navigate<ViewModel2>();
this._navigationService.Navigate<ViewModel3>();
我想在我的 WPF 项目和我的移动版本中使用这个重新加载器实现。
您可以尝试使用 IMvxMessenger
并在需要重新加载数据时发布事件。有关的 TabViewModels 订阅该事件并在调用时调用 ReloadData()
。
我看到的另一种实现方式是这样的。
您有一个 TabHostViewModel
,它的视图包含一个 TabControl
,我们要在其中显示三个选项卡:TabOneViewModel
、TabTwoViewModel
和 TabThreeViewModel
。所有这些选项卡视图模型都实现了一个 ITabViewModel
接口。
TabControl
是 Pivot
class 的自定义实现,它显示不同的选项卡视图并确定是否应重新加载导航到的选项卡。
TabHostViewModel
和 ITabViewModel
:
// TabOneViewModel, TabTwoViewModel and TabThreeViewModel should implement this
public interface ITabViewModel
{
bool ShouldReloadBeforeShow { get; }
// This method should reload whatever needs to be reloaded in your ViewModel
void ReloadModel();
}
public class TabHostViewModel : MvxViewModel
{
public IList<TabPage> TabPages { get; set;}
public override Task Initialize()
{
TabPages = new List<TabPage>
{
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabOneViewModel)
},
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabTwoViewModel)
},
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabThreeViewModel)
}
};
}
}
public class TabPage
{
public string Title { get; set; }
public Type ViewModelType { get; set; }
public ITabViewModel ViewModelInstance { get; set; }
}
自定义 TabControl
class:
public class TabControl : Pivot
{
private readonly IMvxViewsContainer _mvxViewsContainer;
private readonly IMvxViewModelLoader _mvxViewModelLoader;
public TabControl()
{
Loaded += TabControl_Loaded;
SelectionChanged += TabControl_SelectionChanged;
_mvxViewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
_mvxViewModelLoader = Mvx.IoCProvider.Resolve<IMvxViewModelLoader>();
}
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedTab = (TabPage) SelectedItem;
if (selectedTab.ViewModelInstance != null && selectedTab.ViewModelInstance.ShouldReloadBeforeShow)
selectedTab.ViewModelInstance.ReloadModel();
}
private void TabControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (var item in Items)
{
var tabPage = item as TabPage;
var view = CreateViewByViewModelType(tabPage.ViewModelType);
var viewModel = CreateViewModelByViewModelType(tabPage.ViewModelType);
tabPage.ViewModelInstance = viewModel;
view.ViewModel = viewModel;
tabPage.View = view;
}
Loaded -= TabControl_Loaded;
}
private MvxWindowsView CreateViewByViewModelType(Type viewModelType)
{
var viewType = _mvxViewsContainer.GetViewType(viewModelType);
if (viewType == null)
throw new MvxException("View Type not found for " + viewModelType);
var viewObject = Activator.CreateInstance(viewType);
if (viewObject == null)
throw new MvxException("View not loaded for " + viewType);
var view = viewObject as IMvxWindowsView;
if (view == null)
throw new MvxException("Loaded View is not a IMvxWindowsView " + viewType);
return view;
}
public IMvxViewModel CreateViewModelByViewModelType(Type viewModelType)
{
var viewModelRequest = new MvxViewModelRequest(viewModelType);
var viewModel = _mvxViewModelLoader.LoadViewModel(viewModelRequest, null);
return viewModel;
}
}
在你的 TabHostView
:
中使用 TabControl
<controls:TabControl x:Name="TabHostControl" ItemsSource="{Binding TabPages}">
<controls:TabControl.HeaderTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Title}" FontSize="15" />
</StackPanel>
</DataTemplate>
</controls:TabControl.HeaderTemplate>
<controls:TabControl.ItemTemplate>
<DataTemplate>
<ContentPresenter VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Content="{Binding View}" />
</DataTemplate>
</controls:TabControl.ItemTemplate>
</controls:TabControl>
请注意,您需要指定选项卡控件的位置,因此您还需要将以下内容添加到 TabHostView
:
xmlns:controls="using:NAMESPACE_OF_TABCONTROL_HERE"
如何在加载的视图模型中执行方法?
我的结构;
MainView(TabControl) - MainViewModel
View1(Tab1) - ViewModel1
View2(Tab2) - ViewModel2
View3(Tab3) - ViewModel3
在每个 ViewModel 中都有一个 ReloadData() 方法,它从我的数据库中加载一些数据。他们已经像这样在构造函数中被解雇了;
public ViewModel1()
{
ReloadData();
}
private async void ReloadData(){ }
导航到 MainViewModel 时,它将直接(在 ViewAppeared-Method 中)导航到选项卡;
this._navigationService.Navigate<ViewModel1>();
this._navigationService.Navigate<ViewModel2>();
this._navigationService.Navigate<ViewModel3>();
我想在我的 WPF 项目和我的移动版本中使用这个重新加载器实现。
您可以尝试使用 IMvxMessenger
并在需要重新加载数据时发布事件。有关的 TabViewModels 订阅该事件并在调用时调用 ReloadData()
。
我看到的另一种实现方式是这样的。
您有一个 TabHostViewModel
,它的视图包含一个 TabControl
,我们要在其中显示三个选项卡:TabOneViewModel
、TabTwoViewModel
和 TabThreeViewModel
。所有这些选项卡视图模型都实现了一个 ITabViewModel
接口。
TabControl
是 Pivot
class 的自定义实现,它显示不同的选项卡视图并确定是否应重新加载导航到的选项卡。
TabHostViewModel
和 ITabViewModel
:
// TabOneViewModel, TabTwoViewModel and TabThreeViewModel should implement this
public interface ITabViewModel
{
bool ShouldReloadBeforeShow { get; }
// This method should reload whatever needs to be reloaded in your ViewModel
void ReloadModel();
}
public class TabHostViewModel : MvxViewModel
{
public IList<TabPage> TabPages { get; set;}
public override Task Initialize()
{
TabPages = new List<TabPage>
{
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabOneViewModel)
},
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabTwoViewModel)
},
new TabPage {
Title = "Tab one",
ViewModelType = typeof(TabThreeViewModel)
}
};
}
}
public class TabPage
{
public string Title { get; set; }
public Type ViewModelType { get; set; }
public ITabViewModel ViewModelInstance { get; set; }
}
自定义 TabControl
class:
public class TabControl : Pivot
{
private readonly IMvxViewsContainer _mvxViewsContainer;
private readonly IMvxViewModelLoader _mvxViewModelLoader;
public TabControl()
{
Loaded += TabControl_Loaded;
SelectionChanged += TabControl_SelectionChanged;
_mvxViewsContainer = Mvx.IoCProvider.Resolve<IMvxViewsContainer>();
_mvxViewModelLoader = Mvx.IoCProvider.Resolve<IMvxViewModelLoader>();
}
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedTab = (TabPage) SelectedItem;
if (selectedTab.ViewModelInstance != null && selectedTab.ViewModelInstance.ShouldReloadBeforeShow)
selectedTab.ViewModelInstance.ReloadModel();
}
private void TabControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (var item in Items)
{
var tabPage = item as TabPage;
var view = CreateViewByViewModelType(tabPage.ViewModelType);
var viewModel = CreateViewModelByViewModelType(tabPage.ViewModelType);
tabPage.ViewModelInstance = viewModel;
view.ViewModel = viewModel;
tabPage.View = view;
}
Loaded -= TabControl_Loaded;
}
private MvxWindowsView CreateViewByViewModelType(Type viewModelType)
{
var viewType = _mvxViewsContainer.GetViewType(viewModelType);
if (viewType == null)
throw new MvxException("View Type not found for " + viewModelType);
var viewObject = Activator.CreateInstance(viewType);
if (viewObject == null)
throw new MvxException("View not loaded for " + viewType);
var view = viewObject as IMvxWindowsView;
if (view == null)
throw new MvxException("Loaded View is not a IMvxWindowsView " + viewType);
return view;
}
public IMvxViewModel CreateViewModelByViewModelType(Type viewModelType)
{
var viewModelRequest = new MvxViewModelRequest(viewModelType);
var viewModel = _mvxViewModelLoader.LoadViewModel(viewModelRequest, null);
return viewModel;
}
}
在你的 TabHostView
:
TabControl
<controls:TabControl x:Name="TabHostControl" ItemsSource="{Binding TabPages}">
<controls:TabControl.HeaderTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding Title}" FontSize="15" />
</StackPanel>
</DataTemplate>
</controls:TabControl.HeaderTemplate>
<controls:TabControl.ItemTemplate>
<DataTemplate>
<ContentPresenter VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Content="{Binding View}" />
</DataTemplate>
</controls:TabControl.ItemTemplate>
</controls:TabControl>
请注意,您需要指定选项卡控件的位置,因此您还需要将以下内容添加到 TabHostView
:
xmlns:controls="using:NAMESPACE_OF_TABCONTROL_HERE"