我有一个TaskStatus到布尔转换器,它在XAML中为Windows Store应用程序(通用应用程序)实现IValueConverter接口。
我有三个任务状态,并且我使用IsThreeState =“true”在复选框中启用了不确定状态。
现在虽然IsChecked属性似乎是布尔值?但转换器总是将System.Boolean作为目标类型。无论我返回什么(例如null)总是转换为false,因此我无法在我的复选框中获得第三个状态。
有没有办法在我的转换器中指定TargetType或返回null,以便IsChecked作为输入获取null,从而显示第三个状态?
这是转换器:
public class TaskStatusToCheckBoxStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var taskStatus = (TaskStatus) value;
switch (taskStatus)
{
case TaskStatus.Open:
return false;
case TaskStatus.InProgress:
return null;
case TaskStatus.Done:
return true;
default:
throw new ArgumentOutOfRangeException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
var checkBoxState = (Boolean?) value;
if (checkBoxState == null)
return TaskStatus.InProgress;
if (checkBoxState.Value)
return TaskStatus.Done;
return TaskStatus.Open;
}
}
复选框的XAML代码
<CheckBox x:Name="CheckBoxTaskState"
IsThreeState="True"
IsChecked="{Binding Status,
Converter={StaticResource TaskStatusToCheckBoxStateConverter},
Mode=TwoWay}">
</CheckBox>
答案 0 :(得分:2)
根据[this] [1]:目前还不支持在WinRT中绑定到可空类型。对于未记录的规则,该怎么办?现在你知道了。
从这个开始
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
private void NullButton_Click(object sender, RoutedEventArgs e)
{ this.State = null; }
private void FalseButton_Click(object sender, RoutedEventArgs e)
{ this.State = false; }
private void TrueButton_Click(object sender, RoutedEventArgs e)
{ this.State = true; }
bool? _State = null;
public bool? State { get { return _State; } set { SetProperty(ref _State, value); } }
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
void SetProperty<T>(ref T storage, T value, [System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (!object.Equals(storage, value))
{
storage = value;
if (PropertyChanged != null)
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
这个
<Grid x:Name="grid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel Orientation="Horizontal">
<Button Click="TrueButton_Click" Content="True" />
<Button Click="FalseButton_Click" Content="False" />
<Button Click="NullButton_Click" Content="Null" />
</StackPanel>
<TextBlock Text="{Binding State}" />
<CheckBox x:Name="checkBox"
Content="Hello three-state"
IsThreeState="True"
IsChecked="{Binding State, Mode=TwoWay}" />
</StackPanel>
</Grid>
您可以在“输出”窗口中验证此错误。它的内容如下:
错误:转换器无法转换类型&#39;布尔&#39;的值输入&#39; IReference
1<Boolean>'; BindingExpression: Path='State' DataItem='App4.MainPage'; target element is 'Windows.UI.Xaml.Controls.CheckBox' (Name='checkBox'); target property is 'IsChecked' (type 'IReference
1&#39;)。
我对此并不满意。因此,让我们使用附加属性解决它。
public class NullableCheckbox : DependencyObject
{
public static bool GetEnabled(DependencyObject obj)
{ return (bool)obj.GetValue(EnabledProperty); }
public static void SetEnabled(DependencyObject obj, bool value)
{ obj.SetValue(EnabledProperty, value); }
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(NullableCheckbox), new PropertyMetadata(false, EnabledChanged));
private static void EnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as CheckBox;
if ((bool)e.NewValue)
{
var binding = new Binding
{
Path = new PropertyPath("IsChecked"),
Mode = BindingMode.TwoWay,
Source = checkbox,
};
checkbox.SetBinding(NullableCheckbox.InternalStateProperty, binding);
}
}
private static object GetInternalState(DependencyObject obj)
{ return (object)obj.GetValue(InternalStateProperty); }
private static void SetInternalState(DependencyObject obj, object value)
{ obj.SetValue(InternalStateProperty, value); }
private static readonly DependencyProperty InternalStateProperty =
DependencyProperty.RegisterAttached("InternalState", typeof(object),
typeof(NullableCheckbox), new PropertyMetadata(null, InternalStateChanged));
private static void InternalStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{ SetIsChecked(d, (object)e.NewValue); }
public static object GetIsChecked(DependencyObject obj)
{ return (object)obj.GetValue(IsCheckedProperty); }
public static void SetIsChecked(DependencyObject obj, object value)
{ obj.SetValue(IsCheckedProperty, value); }
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked", typeof(object),
typeof(NullableCheckbox), new PropertyMetadata(default(object), IsCheckedChanged));
private static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as CheckBox;
bool? newvalue = null;
if (e.NewValue is bool?)
newvalue = (bool?)e.NewValue;
else if (e.NewValue != null)
{
bool newbool;
if (!bool.TryParse(e.NewValue.ToString(), out newbool))
return;
newvalue = newbool;
}
if (!checkbox.IsChecked.Equals(newvalue))
checkbox.IsChecked = newvalue;
}
}
您的XAML只会改变如下:
<CheckBox Content="Hello three-state"
IsThreeState="True"
local:NullableCheckbox.Enabled="true"
local:NullableCheckbox.IsChecked="{Binding State, Mode=TwoWay}" />
常规的IsChecked属性并不重要,它将被附加属性覆盖。您的viewmodel可以保持不变。这真的很神奇,是吧?
祝你好运!