我有一个数据绑定到ViewModel的窗口。 ViewModel具有许多属性,其中一些属性很难评估,用户并不总是需要它们。
我想要做的是将这些属性数据绑定到包含在不同未扩展扩展器中的控件。当用户扩展扩展器时,我希望绑定控件和要评估的属性。如果用户未展开扩展器,则不应评估属性,并且不会产生成本。
我当然可以使用扩展器中的事件来做这件事,但我正在尝试找到一个很好的MVVM方法。有什么建议吗?
答案 0 :(得分:2)
@Alain的建议看起来很有趣。
此外,由于评估的属性很昂贵,因此您还应该查看异步绑定和优先级绑定。
异步示例:
<TextBox Text={Binding Path=Description, IsAsync="True"}/>
设置IsAsync = True将阻止绑定评估阻止UI线程。
您还可以使用优先级绑定,这是一种多重绑定形式:
<Grid>
<Grid.DataContext>
<Samples:PriorityBindingViewModel/>
</Grid.DataContext>
<TextBox>
<TextBox.Text>
<PriorityBinding>
<Binding Path="ExpensiveProperty" Mode="OneWay" IsAsync="True"/>
<Binding Path="LessExpensiveProperty" Mode="OneWay" IsAsync="True"/>
<Binding Path="LeastExpensiveProperty" Mode="OneWay" IsAsync="True"/>
</PriorityBinding>
</TextBox.Text>
</TextBox>
</Grid>
从上到下优先评估绑定。这允许你说出一个“加载......”#39;最低优先级绑定(LeastExpensiveProperty)中的消息,同时评估高优先级但速度较慢的绑定。
public class PriorityBindingViewModel
{
private string _expensiveProperty;
private string _lessExpensiveProperty;
public PriorityBindingViewModel()
{
ExpensiveProperty = "Loaded";
LessExpensiveProperty = "Still loading";
LeastExpensiveProperty = "Loading";
}
public string ExpensiveProperty
{
get
{
// Thread.Sleep is in place of an 'expensive' operation.
// Just in case anyone doesn't realize.
Thread.Sleep(8000);
return _expensiveProperty;
}
private set { _expensiveProperty = value; }
}
public string LessExpensiveProperty
{
get
{
// Same here.
Thread.Sleep(3000);
return _lessExpensiveProperty;
}
private set { _lessExpensiveProperty = value; }
}
public string LeastExpensiveProperty { get; private set; }
}
答案 1 :(得分:1)
这样的事情会起作用吗?
<Expander Header="Diagnostics" IsExpanded="False">
<Expander.Style>
<Style TargetType="Expander">
<Setter Property="DataContext" Value="{x:Null}" />
<Style.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.Diagnostics}" />
</Trigger>
</Style.Triggers>
</Style>
</Expander.Style>
<TextBlock Text="{Binding TestValue}" />
</Expander>
如果您只想将扩展绑定作为父窗口的datacontext,那么可能这会在触发器中起作用:
<Setter Property="DataContext" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext}" />
答案 2 :(得分:1)
<Expander Expanded="Expander_Expanded">
<....
</Expander>
in .cs:
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
var expander = (Expander)sender;
if(expander.DataContext == null)
expander.DataContext = ViewModel;
}