我们的项目需要绑定控件的许多属性,例如
Height
、Width
、MinHeight
、Row
、Column
、rowspan
...等。在这样做时,我们观察到绑定错误当这些值是 null
时,我们将从 DB 获得。
为了说明这一点,我的 MainWindow.xaml.cs 看起来像这样。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//TextWidth id null
TextBlockSize1 = new ItemSize() { TextHeight=20 };
//TextWidth is null
TextBlockSize2 = new ItemSize() { TextWidth = 40 };
//TextHeight is null and TextWidth is null
TextBlockSize3 = new ItemSize() { TextWidth = 40 };
textblock1.DataContext = TextBlockSize1;
textblock2.DataContext = TextBlockSize2;
textblock3.DataContext = TextBlockSize3;
}
public ItemSize TextBlockSize1 { get; set; }
public ItemSize TextBlockSize2 { get; set; }
public ItemSize TextBlockSize3 { get; set; }
}
public class ItemSize
{
public double? TextHeight { get; set; }
public double? TextWidth { get; set; }
}
和 MainWindow.xaml 看起来像这样。
<Window x:Class="WPfAppln1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:WPfAppln1.Controls"
Title="MainWindow" Height="350" Width="525">
<StackPanel >
<TextBlock Name="textblock1" Text=" TextBlock 1" Width="{Binding TextWidth}" Height="{Binding TextHeight}"></TextBlock>
<TextBlock Name="textblock2" Text=" TextBlock 2" Width="{Binding TextWidth}" Height="{Binding TextHeight}"></TextBlock>
<TextBlock Name="textblock3" Text=" TextBlock 3" Width="{Binding TextWidth, TargetNullValue=Auto}" Height="{Binding TextHeight, TargetNullValue=Auto}"></TextBlock>
</StackPanel>
</Window>
输出窗口中显示以下绑定错误:
System.Windows.Data Error: 5 : 'WPfAppln1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Value produced by BindingExpression is not valid for target property.; Value='<null>' BindingExpression:Path=TextWidth; DataItem='ItemSize' (HashCode=43929715); target element is 'TextBlock' (Name='textblock1'); target property is 'Width' (type 'Double')
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='<null>' BindingExpression:Path=TextHeight; DataItem='ItemSize' (HashCode=57104612); target element is 'TextBlock' (Name='textblock2'); target property is 'Height' (type 'Double')
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='<null>' BindingExpression:Path=TextHeight; DataItem='ItemSize' (HashCode=59587750); target element is 'TextBlock' (Name='textblock3'); target property is 'Height' (type 'Double')
The thread '<No Name>' (0x2c60) has exited with code 0 (0x0).
由于这些错误,应用程序需要很长时间才能加载屏幕。
所以问题是如何在绑定到 wpf 控件时容纳可为 null 的值,以及当绑定值为 null 时如何为控件的宽度属性提供默认值(例如“auto”)。
TargetNullValue
(如果源为空)或FallbackValue
(如果绑定失败,例如DataContext
是null
)
更新:
感谢 Dean 指出这一点,我错误地认为
Auto
会起作用(即 TypeConverter
将负责转换)。
但是,您仍然可以使用 auto 属性并使用
Auto
标记扩展在 XAML 中提供
x:Static
值,如下 -
<TextBlock Name="textblock1" Text=" TextBlock 1"
Height="{Binding TextHeight, TargetNullValue={x:Static System:Double.NaN},
FallbackValue={x:Static System:Double.NaN}}">
</TextBlock>
Value="{x:Static System:Double.NaN}"
也可以用在像这样的DataTrigger
方法中 -
<TextBlock.Style>
<Style>
<Setter Property="Control.Width" Value="{Binding Path=TextWidth}" />
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=TextWidth}"
Value="{x:Null}">
<Setter Property="Control.Width" Value="{x:Static System:Double.NaN}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
注意:需要此命名空间 -
xmlns:System="clr-namespace:System;assembly=mscorlib"
旧代码:
<TextBlock Name="textblock1" Text=" TextBlock 1" Width="{Binding TextWidth}"
Height="{Binding TextHeight, TargetNullValue=Auto, FallbackValue=Auto }">
</TextBlock>
另一种解决方案可以是使用这样的触发器 -
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=TextWidth}"
Value="{x:Null}">
<Setter Property="Control.Width" Value="Auto" />
</DataTrigger>
<DataTrigger
Binding="{Binding Path=TextHeight}"
Value="{x:Null}">
<Setter Property="Control.Height" Value="Auto" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
最简单的解决方案(在我看来)是不使用自动属性。
例如
private double textHeight = Double.NaN;
public double TextHeight
{
get { return textHeight; }
set { textHeight = value; }
}
private double textWidth = Double.NaN;
public double TextWidth
{
get { return textWidth; }
set { textWidth = value; }
}
如果您的两个
double?
属性并不绝对需要为空,您可以将它们设置为常规 double
属性。默认为 0。
如果这是不可能的,或者 0 是不可接受的默认值,我自己会倾向于使用 FallbackValue 解决方案。如果您的默认值必须为“自动”(如上所述),则无法将“自动”设置为
FallbackValue
。
Height和Width默认值不为0;它是 Double.NaN。 高度和宽度支持未设置“自动”值的能力。 由于 Height 和 Width 是双精度值,因此使用 Double.NaN 作为 表示此“自动”行为的特殊值。 (来自 http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.width(v=VS.95).aspx)
如果你不能将
Double.NaN
设置为FallbackValue
(我没有尝试过),我会自己使用转换器。如果目标值为 null
,则返回 Double.NaN
。 http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx了解有关 IVAlueConverter 的更多信息。
我可以确认以下来自
akjoshi
的代码工作得很好。我在 GroupBox
中使用了它,然后用 MaxWidth
和 MaxHeight
扩展了它
<GroupBox Height="{Binding Height, TargetNullValue={x:Static System:Double.NaN}}" MaxHeight="{Binding MaxHeight, TargetNullValue={x:Static System:Double.PositiveInfinity}}"
Width="{Binding Width, TargetNullValue={x:Static System:Double.NaN}}" MaxWidth="{Binding MaxWidth, TargetNullValue={x:Static System:Double.PositiveInfinity}}" >
<!--Some code-->
</GroupBox>
重要的部分是不要忘记添加:
xmlns:System="clr-namespace:System;assembly=mscorlib"