WPF: BindingExpression и Nullable<T>
- modified:
- reading: 2 minutes
Если прописывать Path в Binding на типы Nullable<T> на свойство HasValue, такие как int?, bool? и другие, то можно увидеть неожиданные результаты, а точнее работать данный биндинг не будет. Давайте рассмотрим данный случай подробнее.
Итак, предположим в нашем коде присутствует следующая модель данных:
using System;
namespace WpfApplicationHasValue
{
class SampleModel
{
public SampleModel()
{
SampleValue2 = 0;
}
public int? SampleValue { get; set; }
public int? SampleValue2 { get; set; }
}
}
Получается, что SampleValue равен null и SampleValue.HasValue возвращает false. Используем данную модель в WPF приложении:
<Window x:Class="WpfApplicationHasValue.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplicationHasValue="clr-namespace:WpfApplicationHasValue"
Title="MainWindow" Height="240" Width="500"
DataContext="{DynamicResource ResourceKey=SampleModel}">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<WpfApplicationHasValue:SampleModel x:Key="SampleModel" />
</Window.Resources>
<StackPanel >
<TextBlock Visibility="{Binding Path=SampleValue.HasValue, Converter={StaticResource ResourceKey=BooleanToVisibilityConverter}}">
Must be InVisible
</TextBlock>
<TextBlock Visibility="{Binding Path=SampleValue2.HasValue, Converter={StaticResource ResourceKey=BooleanToVisibilityConverter}}">
Must be Visible
</TextBlock>
</StackPanel>
</Window>
На размещенных двух TextBlock’ах мы повесили Binding на свойства Visiblility с конвертером из bool в Visibility. Конечно мы ожидаем, как я и написал в телах TextBlock такого результата, что первый должен быть не видимым, но такого не произойдет, вместо этого в Output окне мы увидим:
System.Windows.Data Error: 40 : BindingExpression path error: 'HasValue' property not found on 'object' ''Int32' (HashCode=0)'. BindingExpression:Path=SampleValue2.HasValue; DataItem='SampleModel' (HashCode=6257078); target element is 'TextBlock' (Name=''); target property is 'Visibility' (type 'Visibility')
Проблема конечно же в разборе самого Path нашего Binding, и очевидно, что сам WPF тут не причем. Разбор данного пути будет проходить в два этапа:
1. Получаем PropertyInfo для свойства “SampleValue” и вызываем pi.GetValue(item) для получения значения x.
2. Получаем PropertyInfo для свойства “HasValue” и вызываем pi.GetValue(x) для получения финального результата.
Ну и проблема, собственно, в том, что несмотря на то, что pi в первом шаге имеет PropertyType = typeof(Nullable<int>) как и следовало ожидать, величина x возвращаемая методом GetValue возвращается или int или null, но не Nullable<int>. Следовательно шаг 2 не удается, поскольку x не имеет свойство “HasValue”.
В итоге, WPF не может поддерживать свойства HasValue (или Value) в пути биндига, пока CLR (Reflection) не изменит логику в отношении возвращаемых значений типов Nullable<T>, а такого, скорее всего, не будет.
Само собой, это не является проблемой, и если даже и возникнет такая ситуация, то решить ее можно легко. В основном, данный топик просто для предоставления некоторых основ WPF.
See Also
- WPF - использование навигации по страницам, добавление контролов в NavigationWindow
- WPF – MenuItem и важное свойство CommandTarget
- WPF: Как сделать XamlParseException на английском языке.
- WPF: Animated Wait Control в Expression Blend 3
- Работа с окнами как в Windows 7 при помощи hotkeys: Win + [Up|Down|Left|Right]