Như đã nói ở in @Tomas Levesque's answer to a duplicate of this question, điều đơn giản nhất mà sẽ làm việc là để trì hoãn sự ràng buộc của các giá trị bằng cách thêm một mức độ inditection qua một ContentTemplate
DataTemplate
: -
<TabControl>
<TabItem Header="A" Content="{Binding A}">
<TabItem.ContentTemplate>
<DataTemplate>
<local:AView DataContext="{Binding Value}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
<TabItem Header="B" Content="{Binding B}">
<TabItem.ContentTemplate>
<DataTemplate>
<local:BView DataContext="{Binding Value}" />
</DataTemplate>
</TabItem.ContentTemplate>
</TabItem>
</TabControl>
Sau đó, VM chỉ cần có một số sự lười biếng: -
public class PageModel
{
public PageModel()
{
A = new Lazy<ModelA>(() => new ModelA());
B = new Lazy<ModelB>(() => new ModelB());
}
public Lazy<ModelA> A { get; private set; }
public Lazy<ModelB> B { get; private set; }
}
Và bạn đã hoàn tất.
Trong trường hợp đặc biệt của tôi, tôi có lý do để tránh điều đó sắp xếp XAML nói riêng và cần thiết để có thể xác định DataTemplate
s của tôi trong Resources
. Điều này gây ra sự cố là a DataTemplate
can only be x:Type
d and hence Lazy<ModelA>
can not be expressed via that (and custom markup annotations are explicitly forbidden in such definitions).
Trong trường hợp đó, con đường đơn giản nhất xung quanh đó là để xác định một loại tối thiểu có nguồn gốc cụ thể: -
public class PageModel
{
public PageModel()
{
A = new LazyModelA(() => new ModelA());
B = new LazyModelB(() => new ModelB());
}
public LazyModelA A { get; private set; }
public LazyModelB B { get; private set; }
}
Sử dụng một helper như vậy:
public class LazyModelA : Lazy<ModelA>
{
public LazyModelA(Func<ModelA> factory) : base(factory)
{
}
}
public class LazyModelB : Lazy<ModelB>
{
public LazyModelB(Func<ModelB> factory) : base(factory)
{
}
}
nào sau đó có thể được tiêu thụ thẳng thắn qua DataTemplate
s: -
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:LazyModelA}">
<local:ViewA DataContext="{Binding Value}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:LazyModelB}">
<local:ViewB DataContext="{Binding Value}" />
</DataTemplate>
</UserControl.Resources>
<TabControl>
<TabItem Header="A" Content="{Binding A}"/>
<TabItem Header="B" Content="{Binding B}"/>
</TabControl>
Người ta có thể tạo ứng dụng đó roach chung chung hơn bằng cách giới thiệu một ViewModel loại lỏng lẻo:
public class LazyModel
{
public static LazyModel Create<T>(Lazy<T> inner)
{
return new LazyModel { _get =() => inner.Value };
}
Func<object> _get;
LazyModel(Func<object> get)
{
_get = get;
}
public object Value { get { return _get(); } }
}
này cho phép bạn viết mã NET nhỏ gọn hơn:
public class PageModel
{
public PageModel()
{
A = new Lazy<ModelA>(() => new ModelA());
B = new Lazy<ModelB>(() => new ModelB());
}
public Lazy<ModelA> A { get; private set; }
public Lazy<ModelB> B { get; private set; }
Tại giá thêm một lớp sugaring/detyping:
// Ideal for sticking in a #region :)
public LazyModel AXaml { get { return LazyModel.Create(A); } }
public LazyModel BXaml { get { return LazyModel.Create(B); } }
Và cho phép Xaml là:
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:ModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ModelB}">
<local:ViewB />
</DataTemplate>
<DataTemplate DataType="{x:Type local:LazyModel}">
<ContentPresenter Content="{Binding Value}" />
</DataTemplate>
</UserControl.Resources>
<TabControl>
<TabItem Header="A" Content="{Binding AXaml}" />
<TabItem Header="B" Content="{Binding BXaml}" />
</TabControl>
+1 Bạn sẽ sử dụng tùy chọn thứ hai một cách tự nhiên nếu bạn đang thực hiện MVVM. –
Việc sử dụng tùy chọn thứ hai có làm cho các tab bị mất trạng thái khi chúng được tải không? – yclevine
Có, nhưng bạn có thể sử dụng các thuộc tính trong MyBusinessObject để xác định trạng thái có thể được đồng bộ hóa với trạng thái trực quan và bất kỳ trạng thái điều khiển logic nào khác. –