我遇到了一种奇怪的绑定行为,描述为here。我做了很多故障排除,我得出结论,最可能的问题在于我如何设置每个标签视图的DataContext
。
我有一个TabControl
,ItemsSource
绑定到ViewModels
列表。
MainView:
<TabControl ItemsSource="{Binding TabList}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:Tab1ViewModel}">
<v:Tab1 />
</DataTemplate>
</TabControl.Resources>
...
</TabControl>
MainViewModel:
public ObservableCollection<TabViewModelBase> TabList { get; set; }
public MainViewModel()
{
this.TabList = new ObservableCollection<TabViewModelBase>();
// Tab1ViewModel is derived from TabViewModelBase
this.TabList.Add(new Tab1ViewModel());
}
所以,现在MainViewModel
有一个TabViewModelBase
列表,我认为这是正确的MVVM方式。 Tab1
的视图(TabViewModelBase
)是使用DataTemplate
定义的。
这就是问题所在:
Tab1:
<UserControl.Resources>
<vm:Tab1ViewModel x:Key="VM" />
</UserControl.Resources>
<UserControl.DataContext>
<StaticResourceExtension ResourceKey="VM" />
</UserControl.DataContext>
我想大多数人也会这样做,但...... 使用这种方法有一些非常错误!
在MainViewModel
中,我手动实例化了Tab1ViewModel
。在MainView
中,我使用DataTemplate
告诉视图在看到Tab1
时使用Tab1ViewModel
。这意味着MainView
将实例化Tab1
类的对象。
现在,Tab1
需要其DataContext
与自己的Tab1ViewModel
绑定,因此我们使用StaticResource
添加一个Tab1ViewModel
,但这是一个全新的实例!
我需要将DataContext
设置回我在MainViewModel
中实例化的原始版本。那么,如何在DataContext
内设置Tab1
的{{1}}?
答案 0 :(得分:3)
您不必在XAML中指定vm:Tab1ViewModel
个新实例。您也不需要明确定义DataContext
。只要ViewModel
的类型与ViewModel
中定义的类型DataTemplate
相匹配,view
的类型将会呈现DataContext
ViewModel
public ObservableCollection<TabViewModelBase> TabList { get; set; }
public MainViewModel()
{
this.TabList = new ObservableCollection<TabViewModelBase>();
this.TabList.Add(new Tab1ViewModel1());
this.TabList.Add(new Tab1ViewModel2());
}
{1}} DataTemplate
。例如,如果list有两个对象,如下所示:
<TabControl ItemsSource="{Binding TabList}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:Tab1ViewModel}">
<v:Tab1 />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:Tab1ViewModel2}">
<v:Tab2 />
</DataTemplate>
</TabControl.Resources>
并且您的Tab1
是:
Tab2
...
然后两个标签将呈现
Tab1
&amp;Tab1ViewModel1
(原因列表有2个项目)。DataContext
Tab2
为Tab1ViewModel2
,DataContext
为DataContext
var randDate = new Date(2016, 04, 29, 10, 15); randDate.setHours(0); randDate.setMinutes(0); randDate.setSeconds(0); randDate.setMilliseconds(0); var target = new Date(2016, 04, 29); target.setHours(0); target.setMinutes(0); target.setSeconds(0); target.setMilliseconds(0); console.log(target.getTime() === randDate.getTime()); //output: true
为var randDate = new Date(2016, 04, 29, 10, 15); //randDate is your now() on any day randDate.setHours(0,0,0,0); var now = new Date(); now.setHours(0,0,0,0); //strips h, m, s, ms from var now && var randDate var target = new Date(2016, 04, 29); //set up your target target.setHours(0,0,0,0); //strips h, m, s, ms if needed console.log(target.getTime() === randDate.getTime()); //output: true console.log(target.getTime() === now.getTime()); //output: false (Mon May 09 2016 00:00:00 GMT+0200 (Romance (zomertijd)))
。您无需指定import time now = time.clock() while now + 5 > time.clock(): print time.clock() time.sleep(1) print "Woke up"
明确。 强>
答案 1 :(得分:2)
只是@KyloRen答案的补充:这就是所谓的&#34; ViewModel-First方法&#34;。根据您的viewmodel,选择视图 - &gt;你先拥有viewmodel。
但是,您甚至不需要为您的观看数据模板。为每个视图编写datatemplate会很烦人。
有相同的替代实现&#34; ViewModel-First&#34;原理:
<TabControl ItemsSource="{Binding TabList}">
<TabControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content={Binding Converter={ViewModelToViewConverter}} />
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
ViewModelToViewConverter
接受ViewModel,并根据命名约定为其创建视图。这在基于页面的导航场景中尤其有用,但它是适用于许多情况的通用方法(导航,列表框,项目控件,动态内容演示者等)。
可以找到转换器的示例here - 只需将IocContainer替换为Activator.CreateInstance