我的WPF应用程序被组织为TabControl,每个选项卡包含不同的屏幕.
一个TabItem绑定到需要一点时间才能加载的数据.由于此TabItem表示用户可能很少使用的屏幕,因此我希望在用户选择选项卡之前不加载数据.
我怎样才能做到这一点?
Aka*_*ava 17
标签控件有两种方式,
使用第二种方法并不复杂,但在运行时它肯定会减少它所使用的资源,但是在切换标签时,它可能会稍微慢一些.
您必须创建自定义数据类,如下所示
class TabItemData{
public string Header {get;set;}
public string ResourceKey {get;set;}
public object MyBusinessObject {get;set;}
}
Run Code Online (Sandbox Code Playgroud)
并且您必须创建TabItemData的列表或数组,并且必须将TabControl的项源设置为TabItemData的列表/数组.
然后创建TabControl的ItemTemplate作为绑定"Header"属性的数据模板.
然后创建TabControl的创建ContentTemplate作为包含ContentControl的数据模板,其中ResourceConmplate是在ResourceKey属性中找到的Resource Key的ContentTemplate.
Dan*_*rov 13
可能为时已晚:)但是那些寻找答案的人可以试试这个:
<TabItem>
<TabItem.Style>
<Style TargetType="TabItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Content">
<Setter.Value>
<!-- Your tab item content -->
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Content" Value="{Binding Content, RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>
</TabItem.Style>
</TabItem>
Run Code Online (Sandbox Code Playgroud)
您还可以使用包含"延迟"内容的AttachedProperty创建可重复使用的TabItem样式.如果需要,请告诉我,我会编辑答案.
更新:
附属物:
public class Deferred
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.RegisterAttached(
"Content",
typeof(object),
typeof(Deferred),
new PropertyMetadata());
public static object GetContent(DependencyObject obj)
{
return obj.GetValue(ContentProperty);
}
public static void SetContent(DependencyObject obj, object value)
{
obj.SetValue(ContentProperty, value);
}
}
Run Code Online (Sandbox Code Playgroud)
TabItem样式:
<Style TargetType="TabItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Content" Value="{Binding Path=(namespace:Deferred.Content), RelativeSource={RelativeSource Self}}"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Content" Value="{Binding Content, RelativeSource={RelativeSource Self}}"/>
</Trigger>
</Style.Triggers>
</Style>
Run Code Online (Sandbox Code Playgroud)
例:
<TabControl>
<TabItem Header="TabItem1">
<namespace:Deferred.Content>
<TextBlock>
DeferredContent1
</TextBlock>
</namespace:Deferred.Content>
</TabItem>
<TabItem Header="TabItem2">
<namespace:Deferred.Content>
<TextBlock>
DeferredContent2
</TextBlock>
</namespace:Deferred.Content>
</TabItem>
</TabControl>
Run Code Online (Sandbox Code Playgroud)
正如在@Tomas Levesque对这个问题的重复的回答中所提到的,最简单的方法是通过以下方式添加一定程度的延迟来推迟值的绑定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>
Run Code Online (Sandbox Code Playgroud)
然后VM只需要有一些懒惰: -
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; }
}
Run Code Online (Sandbox Code Playgroud)
而且你已经完成了.
在我的具体情况,我有理由避免特定的XAML安排,并能够定义我需要DataTemplate
在S Resources
.这会导致一个问题,因为一个DataTemplate
只能是x:Type
d,因此Lazy<ModelA>
不能表示经由(和自定义标记注解明确地在这样的定义被禁止).
在这种情况下,最简单的方法是定义最小的派生混凝土类型: -
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; }
}
Run Code Online (Sandbox Code Playgroud)
使用这样的帮助:
public class LazyModelA : Lazy<ModelA>
{
public LazyModelA(Func<ModelA> factory) : base(factory)
{
}
}
public class LazyModelB : Lazy<ModelB>
{
public LazyModelB(Func<ModelB> factory) : base(factory)
{
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以通过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>
Run Code Online (Sandbox Code Playgroud)
通过引入松散类型的ViewModel,可以使该方法更通用:
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(); } }
}
Run Code Online (Sandbox Code Playgroud)
这允许您编写更紧凑的.NET代码:
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; }
Run Code Online (Sandbox Code Playgroud)
以添加糖/脱胶层为代价:
// Ideal for sticking in a #region :)
public LazyModel AXaml { get { return LazyModel.Create(A); } }
public LazyModel BXaml { get { return LazyModel.Create(B); } }
Run Code Online (Sandbox Code Playgroud)
并允许Xaml:
<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>
Run Code Online (Sandbox Code Playgroud)