如何在每次使用Prism的MVVM应用程序中选择TabItem时运行方法

时间:2018-04-30 13:55:20

标签: c# wpf mvvm prism

我一直试图实现这一点,到目前为止还没能做到这一点,尽管感觉这应该是容易的。

困难来自于我使用MVVM模式实现了WPF应用程序。现在,这是我对模式和框架的第一次尝试,因此几乎可以保证我在尝试遵循MVVM指南时犯了错误。

我的实施

我有三个视图与他们各自的ViewModel(使用Prism的AutoWireViewModel方法连线)。 MainViewTabControlTabItem个,每个包含Frame容器,其中Source设置为其他两个View中的一个MainView }}秒。以下代码摘自<TabControl Grid.Row="1" Grid.Column="1"> <TabItem Header="Test"> <!--TestView--> <Frame Source="View1.xaml"/> </TabItem> <TabItem Header="Results"> <!--ResultsView--> <Frame Source="View2.xaml"/> </TabItem> </TabControl>

TabItem

我的问题

每当有人更改为特定View时,我都希望运行一种方法来更新Button中包含的其中一个WPF控件。该方法已经实现并绑定到Event,但理想情况下,不需要任何按钮,我希望有某种{{1}}来实现这一点。

我提前感谢所有帮助。

4 个答案:

答案 0 :(得分:1)

例如,您可以处理Loaded的{​​{1}}事件,以便在最初加载视图后调用方法或调用视图模型的命令:

Page

另一个选项是在public partial class View2 : Page { public View2() { InitializeComponent(); Loaded += View2_Loaded; } private void View2_Loaded(object sender, RoutedEventArgs e) { var viewModel = DataContext as ViewModel2; if (viewModel != null) viewModel.YourCommand.Execute(null); Loaded -= View2_Loaded; } } 处理此问题。您将MainViewModel的{​​{1}}属性绑定到SelectedItem的属性,并将此属性设置为TabControlMainViewModel的实例,具体取决于您要显示的视图类型。

然后,您可以调用任何方法或调用您想要的任何命令。但这是另一个故事,那么您不应该在视图中对ViewModel2进行硬编码,并使用ViewModel2元素来显示TabItems。请看这里举个例子:

Selecting TabItem in TabControl from ViewModel

答案 1 :(得分:0)

好的,我所做的就是创建一个自定义选项卡控件。我将为此逐步写出说明,然后您可以添加编辑功能。

  1. 右键单击您的解决方案,选择添加新项目
  2. 搜索自定义控件库
  3. 高亮显示出现的类的名称,然后右键单击将其重命名为您想要的名称MyTabControl.
  4. 将Prism.Wpf添加到新项目
  5. 将对新项目的引用添加到您需要它的位置。我需要添加到主应用程序,但如果你有一个只有视图的单独项目,那么你也需要将它添加到那个。
  6. TabControl继承您的自定义控件:

    public class MyTabControl:TabControl

  7. 您会注意到项目中有一个Themes文件夹,您需要打开Generic.xaml并进行编辑。它应该看起来像:

    TargetType="{x:Type local:MyTabControl}" BasedOn="{StaticResource {x:Type TabControl}}"出于某种原因,这不会让我展示样式标签,但他们也需要在那里

  8. 请查看此代码,我是从Add A Command To Custom Control

    获取的
    public class MyTabControl : TabControl
     {
         static MyTabControl()
         {
             DefaultStyleKeyProperty.OverrideMetadata(typeof(MyTabControl), new FrameworkPropertyMetadata(typeof(MyTabControl)));
         }
    
         public static readonly DependencyProperty TabChangedCommandProperty = DependencyProperty.Register(
             "TabChangedCommand", typeof(ICommand), typeof(MyTabControl), 
             new PropertyMetadata((ICommand)null,
             new PropertyChangedCallback(CommandCallBack)));
    
         private static void CommandCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
             var myTabControl = (MyTabControl)d;
             myTabControl.HookupCommands((ICommand) e.OldValue, (ICommand) e.NewValue);
         }
    
         private void HookupCommands(ICommand oldValue, ICommand newValue)
         {
            if (oldValue != null)
             {
                 RemoveCommand(oldValue, oldValue);
             }
             AddCommand(oldValue, oldValue);
         }
    
         private void AddCommand(ICommand oldValue, ICommand newCommand)
         {
             EventHandler handler = new EventHandler(CanExecuteChanged);
             var canExecuteChangedHandler = handler;
             if (newCommand != null)
             {
                 newCommand.CanExecuteChanged += canExecuteChangedHandler;
             }
    
         }
    
         private void CanExecuteChanged(object sender, EventArgs e)
         {
             if (this.TabChangedCommand != null)
             {
                 if (TabChangedCommand.CanExecute(null))
                 {
                     this.IsEnabled = true;
                 }
                 else
                 {
                     this.IsEnabled = false;
                 }
             }
         }
    
         private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
         {
             EventHandler handler = CanExecuteChanged;
             oldCommand.CanExecuteChanged -= handler;
         }
    
         public ICommand TabChangedCommand
         {
             get { return (ICommand) GetValue(TabChangedCommandProperty); }
             set { SetValue(TabChangedCommandProperty, value); }
         }
    
    
         public override void OnApplyTemplate()
         {
             base.OnApplyTemplate();
             this.SelectionChanged += OnSelectionChanged;
         }
    
         private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
         {
             if (TabChangedCommand != null)
             {
                 TabChangedCommand.Execute(null);
             }
         }
         }
    
  9. 您需要在窗口或usercontrol中添加名称空间,如:

    xmlns:wpfCustomControlLibrary1="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
    

    这是你的控制:

        <wpfCustomControlLibrary1:MyTabControl TabChangedCommand="{Binding TabChangedCommand}">
            <TabItem Header="View A"></TabItem>
            <TabItem Header="View B"></TabItem>
        </wpfCustomControlLibrary1:MyTabControl>
    

答案 2 :(得分:0)

这就是我如何处理这种要求: 视图:

    <Window.DataContext>
        <local:MainWIndowViewModel/>
    </Window.DataContext>
    <Grid>
        <TabControl Name="tc" ItemsSource="{Binding vms}">
            <TabControl.Resources>
                <DataTemplate DataType="{x:Type local:uc1vm}">
                    <local:UserControl1/>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:uc2vm}">
                    <local:UserControl2/>
                </DataTemplate>
            </TabControl.Resources>
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding TabHeading}"/>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
    </Grid>
</Window>

当它有一个uc1vm时,它将被模板化为视图中的usercontrol1 我绑定到一个视图模型集合,这些视图模型都实现了一个接口,所以我确信我可以转换为该方法并调用方法。

窗口的主视图模型:

    private IDoSomething selectedVM;

    public IDoSomething SelectedVM
    {
        get { return selectedVM; }
        set
        {
            selectedVM = value;
            selectedVM.doit();
            RaisePropertyChanged();
        }
    }

    public ObservableCollection<IDoSomething> vms { get; set; } = new ObservableCollection<IDoSomething>
    {   new uc1vm(),
        new uc2vm()
    };

    public MainWIndowViewModel()
    {

    }

选择选项卡后,所选项目的设置者将传递新值。转换并调用该方法。

我的界面非常简单,因为这只是说明性的:

public interface IDoSomething
{
    void doit();
}

一个示例视图模型,它只是说明性的,并没有做太多事情:

public class uc1vm : IDoSomething
{
    public string TabHeading { get; set; } = "Uc1";
    public void doit()
    {
       // Your code goes here
    }
}

答案 3 :(得分:0)

我感谢您的所有投入,但我找到了另一种解决方案。鉴于@ mm8给出的信息,我利用了Loaded事件,但是在后面的代码中不需要任何代码。

我的解决方案

View中,我希望每次用户选择包含它的TabItem时都能执行此方法,我添加了以下代码:

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

然后在DelegateCommand各自的OnLoadedCommand中简单地实施一个名为View的{​​{1}}。在那个命令中,我称之为我想要的方法。

如果您发现此方法有任何问题,请发表评论!我选择尝试这个,因为它需要对我的代码进行最少量的更改,但我可能会遗漏一些关于解决方案可能导致的问题的重要信息。