我一直试图实现这一点,到目前为止还没能做到这一点,尽管感觉这应该是容易的。
困难来自于我使用MVVM模式实现了WPF应用程序。现在,这是我对模式和框架的第一次尝试,因此几乎可以保证我在尝试遵循MVVM指南时犯了错误。
我的实施
我有三个视图与他们各自的ViewModel(使用Prism的AutoWireViewModel
方法连线)。 MainView
有TabControl
个TabItem
个,每个包含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}}来实现这一点。
我提前感谢所有帮助。
答案 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
的属性,并将此属性设置为TabControl
或MainViewModel
的实例,具体取决于您要显示的视图类型。
然后,您可以调用任何方法或调用您想要的任何命令。但这是另一个故事,那么您不应该在视图中对ViewModel2
进行硬编码,并使用ViewModel2
元素来显示TabItems
。请看这里举个例子:
答案 1 :(得分:0)
好的,我所做的就是创建一个自定义选项卡控件。我将为此逐步写出说明,然后您可以添加编辑功能。
MyTabControl.
从TabControl
继承您的自定义控件:
public class MyTabControl:TabControl
您会注意到项目中有一个Themes文件夹,您需要打开Generic.xaml
并进行编辑。它应该看起来像:
TargetType="{x:Type local:MyTabControl}" BasedOn="{StaticResource {x:Type TabControl}}"
出于某种原因,这不会让我展示样式标签,但他们也需要在那里
请查看此代码,我是从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);
}
}
}
您需要在窗口或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}}。在那个命令中,我称之为我想要的方法。
如果您发现此方法有任何问题,请发表评论!我选择尝试这个,因为它需要对我的代码进行最少量的更改,但我可能会遗漏一些关于解决方案可能导致的问题的重要信息。