2011-09-20 87 views
0

我试图使用MVVM,所以我有:如何在另一个线程之间切换视图?

主窗口:

<Window x:Class="tbtest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <TabControl ItemsSource="{Binding Tabs}" IsSynchronizedWithCurrentItem="True" Grid.Row="0"/> 
     <Button Command="{Binding AddNewTab}" Grid.Row="1">Add new tab</Button> 
    </Grid> 
</Window> 

和视图模型:

public class VM 
{ 
    public VM() 
    { 
     Tabs = new ObservableCollection<Object>(); 
     AddNewTab = new DelegateCommand<object>(ExecAddNewTab); 
    } 

    private void ExecAddNewTab(object obj) 
    { 
     var tab = new SomeTab(); 
     Tabs.Add(tab.View); 
     ThreadPool.QueueUserWorkItem(item => tab.Activate()); 
    } 

    public ObservableCollection<Object> Tabs { get; private set; } 
    public DelegateCommand<object> AddNewTab { get; private set; } 
} 

每个选项卡是独立的视图模型与景观:

public class SomeTab : ITab, INotifyPropertyChanged 
{ 
    public SomeTab() 
    { 
     View = new SomeTabView1 {DataContext = this}; 
    } 

    public string Header { get { return "Header"; } } 
    private object _view; 
    public object View 
    { 
     get { return _view; } 
     private set 
     { 
      _view = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("View")); 
     } 
    } 

    public void Activate() 
    { 
     Thread.Sleep(2000); 

     // Some work 

     Application.Current.Dispatcher.BeginInvoke(new Action<SomeTab>(vm => 
                    { 
// switching views, how can it be done? 
                      vm.View = new SomeTabView2 { DataContext = this }; 

                    }), this); 
    } 

    public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
} 

SomeTabView1 And SomeTabView2 are si使用TextBlock的'View1'和'View2'实现多个WPF UserControl。

我需要的是在Activate方法(即在单独的线程中运行)将View1切换到View2。
我提供的这段代码不起作用。

我该怎么做才能满足需求?谢谢。

回答

0

上面的问题是由于您的代码是“假设”它将通过简单地使用IsSynchronizedWithCurrentItem选择\专注新创建的Tab项目。

您需要将该字段替换为CollectionView。你也应该使用这个CollectionView本身添加新标签。

E.g.

假设你有一个叫ListCollectionViewTabsView源集合为Tabs观察到的集合......

绑定TabControl.ItemsSourceTabsView,然后代替......

var tab = new SomeTab(); 
    Tabs.Add(tab.View); 

使用此...

var tabUi = this.TabsView.AddNew() as SomeTab; 
    this.TabsView.CommitNew(); 
    tabUi.Activate(); 

让我知道这是否有帮助....

+0

很抱歉,但我不明白。我不需要选择/集中新创建的选项卡项目。我需要,那个标签内容会改变。首先 - 我必须在选项卡视图中显示“正在加载...”,并且当所有数据准备好显示时,我需要将视图更改为DagaGrids,TextBoxes等...... – Lari13

1

你的ViewModels不应该查看

工作相反,有你MainViewModel包含SelectedTab属性,并将其绑定到你的TabControl,然后切换选项卡,你只设置SelectedTab。使用DataTemplates告诉WPF如何绘制每个视图模型

主窗口XAML

<Window x:Class="tbtest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     xmlns:local=clr-namespace:MyNamespace> 

    <Window.Resources> 
     <DataTemplate DataType="{x:Type local:SomeTabViewModel1}"> 
      <local:SomeTabView1 /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:SomeTabViewModel2}"> 
      <local:SomeTabView2 /> 
     </DataTemplate> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:SomeTabViewModel3}"> 
      <local:SomeTabView3 /> 
     </DataTemplate> 
    </Window.Resources> 

    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}" 
        IsSynchronizedWithCurrentItem="True" Grid.Row="0"/> 
     <Button Command="{Binding AddNewTab}" Grid.Row="1">Add new tab</Button> 
    </Grid> 
</Window> 

主窗口视图模型

public class VM 
{ 
    public VM() 
    { 
     Tabs = new ObservableCollection<Object>(); 
     AddNewTab = new DelegateCommand<object>(ExecAddNewTab); 
    } 

    private void ExecAddNewTab(object obj) 
    { 
     var tab = new SomeTab(); 
     Tabs.Add(tab); 
     SelectedTab = tab; 

     // This should only run whatever code is needed to initialize the 
     // ViewModel. It should have nothing to do with views 
     ((ITab)tab).Activate(); 
    } 

    public object SelectedTab { get; private set; } 
    public ObservableCollection<Object> Tabs { get; private set; } 
    public DelegateCommand<object> AddNewTab { get; private set; } 
} 
+0

我不需要切换选项卡。我只需要在一个选项卡内切换视图。我需要:创建新的标签页,在此标签页上显示“正在加载...”消息,在后台加载数据,在同一个标​​签中显示加载的数据(数据网格,文本框等)。) – Lari13

+0

在这种情况下,你的'TabViewModel'应该有一个'IsLoading'属性,当它被激活时被设置为'true',并且加载消息和标签内容的可见性应该被绑定到'IsLoading'。您的ViewModels绝不应该处理视图 – Rachel

+0

谢谢。让我们把这个例子复杂化。 'MainWindowView'在一个程序集中,而其他''中的每个'TabViewModel'。现在我有10个不同的'TabViewModels'。我应该在每个(!)'TabView1','TabView2'中写入相同的代码(绑定到IsLoaded属性并使用可见性)?是否有可能创建一个共同的视图“IsLoadingView”并显示它,然后加载内容,将其切换到“TabViewXXX”视图之一? – Lari13

相关问题