返回null布尔以复选框XAML状态转换器 [英] Return null in boolean to checkbox state converter in XAML
问题描述
我有一个TaskStatus布尔转换器,实现了Windows应用商店的应用程序(通用应用程序)的XAML中的IValueConverter接口。
我有三个任务状态,我启用使用IsThreeState =真。
现在虽然物业器isChecked似乎是一个布尔的复选框不确定状态?变频器总是得到System.Boolean为目标类型。无论我回(空为例)总是转换为false,所以我不能让我的复选框第三种状态。
有没有办法要么指定的TargetType在我的转换器或返回空值,使器isChecked得到null作为输入,因此显示第三种状态
下面是转换器:
公共类TaskStatusToCheckBoxStateConverter:的IValueConverter
{
公共对象转换(对象的值,类型TARGETTYPE,对象参数,字符串语言)
{
VAR taskStatus =(TaskStatus)值;
开关(taskStatus)
{
情况下TaskStatus.Open:
返回FALSE;
情况下TaskStatus.InProgress:
返回NULL;
情况下TaskStatus.Done:
返回真;
默认:
抛出新ArgumentOutOfRangeException();
}
}
公共对象ConvertBack(对象的值,类型TARGETTYPE,对象参数,字符串语言)
{
VAR checkBoxState =(布尔?)值;
如果(checkBoxState == NULL)
返回TaskStatus.InProgress;
如果(checkBoxState.Value)
返回TaskStatus.Done;
返回TaskStatus.Open;
}
}
XAML的代码的复选框
<复选框X:NAME =CheckBoxTaskState
IsThreeState =真
器isChecked ={绑定状态,
=转换器的StaticResource {} TaskStatusToCheckBoxStateConverter,
模式=双向}>
< /复选框>
根据[这里] [1]:绑定到可空类型在WinRT中不支持在这个时候。是如何形成的一个未公开的规则?现在你知道了。
开始本
公共密封部分类的MainPage:页面, INotifyPropertyChanged的
{
公众的MainPage()
{
this.InitializeComponent();
this.DataContext =这一点;
}
私人无效NullButton_Click(对象发件人,RoutedEventArgs E)
{this.State = NULL; }
私人无效FalseButton_Click(对象发件人,RoutedEventArgs E)
{this.State = FALSE; }
私人无效TrueButton_Click(对象发件人,RoutedEventArgs E)
{this.State = TRUE; }
布尔? _State = NULL;
公共BOOL?国{{返回_State; }集合{的SetProperty(REF _State,价值); }}
公共事件System.ComponentModel.PropertyChangedEventHandler的PropertyChanged;
无效的SetProperty< T>!(REF T存储,T值,[System.Runtime.CompilerServices.CallerMemberName]字符串参数propertyName = NULL)
{
如果(的Object.Equals(存储,值))
{
存储=价值;
如果(的PropertyChanged!= NULL)
的PropertyChanged(这一点,新System.ComponentModel.PropertyChangedEventArgs(propertyName的));
}
}
}
这
<电网X:NAME =网格背景={ThemeResource ApplicationPageBackgroundThemeBrush}>
< StackPanel中的HorizontalAlignment =中心VerticalAlignment =中心>
< StackPanel的方向=横向>
<按钮单击=TrueButton_ClickCONTENT =真/>
<按钮单击=FalseButton_ClickCONTENT =FALSE/>
<按钮单击=NullButton_ClickCONTENT =空/>
< / StackPanel的>
< TextBlock的文本={绑定状态}/>
<复选框X:NAME =复选框
含量=你好三态
IsThreeState =真
器isChecked ={绑定状态,模式=双向} />
< / StackPanel的>
< /网格和GT;
您可以验证您的输出窗口此错误。它读取像这样:
错误:转换器无法转换类型'布尔'的价值键入'IReference
1<布尔>'; BindingExpression:路径='国家'的DataItem ='App4.MainPage';目标元素是'Windows.UI.Xaml.Controls.CheckBox'(名称=复选框');目标属性器isChecked'(类型'IReference
1)。
块引用>
我不喜欢这种。因此,让我们解决它与附加属性。
公共类NullableCheckbox:DependencyObject的
{
公共静态布尔GetEnabled(DependencyObject的OBJ)
{回报(布尔)obj.GetValue(EnabledProperty);的setEnabled(OBJ的DependencyObject,布尔值)
{obj.SetValue(EnabledProperty,值)}
公共静态无效; }
公共静态只读的DependencyProperty EnabledProperty =
DependencyProperty.RegisterAttached(已启用,typeof运算(布尔)的typeof(NullableCheckbox),新PropertyMetadata(假,EnabledChanged));
私有静态无效EnabledChanged(DependencyObject的D,DependencyPropertyChangedEventArgs E)
{
VAR复选框= D的复选框;
如果((布尔)e.NewValue)
{
变种结合=新的Binding
{
路径=新的PropertyPath(器isChecked),
模式= BindingMode.TwoWay,
来源=复选框,
};
checkbox.SetBinding(NullableCheckbox.InternalStateProperty,绑定);
}
}
私有静态对象GetInternalState(DependencyObject的OBJ)
{回报(对象)obj.GetValue(InternalStateProperty); }
私有静态无效SetInternalState(OBJ的DependencyObject,对象的值)
{obj.SetValue(InternalStateProperty,值); }
私人静态只读的DependencyProperty InternalStateProperty =
DependencyProperty.RegisterAttached(InternalState的typeof(对象),
typeof运算(NullableCheckbox),新PropertyMetadata(NULL,InternalStateChanged));
私有静态无效InternalStateChanged(DependencyObject的D,DependencyPropertyChangedEventArgs E)
{SetIsChecked(D,(对象)e.NewValue); }
公共静态对象GetIsChecked(DependencyObject的OBJ)
{回报(对象)obj.GetValue(IsCheckedProperty); SetIsChecked(OBJ的DependencyObject,对象的值)
{obj.SetValue(IsCheckedProperty,值)}
公共静态无效; }
公共静态只读的DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached(器isChecked的typeof(对象),
typeof运算(NullableCheckbox),新PropertyMetadata(默认值(对象),IsCheckedChanged));
私有静态无效IsCheckedChanged(DependencyObject的D,DependencyPropertyChangedEventArgs E)
{
VAR复选框= D的复选框;
布尔? NEWVALUE = NULL;
如果(e.NewValue是布尔?)
NEWVALUE =(布尔?)e.NewValue;
,否则如果(e.NewValue!= NULL)
{
布尔newbool;
如果
回报率(bool.TryParse(e.NewValue.ToString(),出newbool)!);
NEWVALUE = newbool;
}
如果
checkbox.IsChecked = NEWVALUE(checkbox.IsChecked.Equals(NEWVALUE)!);
}
}
您XAML只会改变这样的:
<复选框CONTENT =你好三态
IsThreeState =真
地方:NullableCheckbox.Enabled =真正的
地方:NullableCheckbox.IsChecked ={绑定状态,模式=双向}/>
常规物业器isChecked不要紧,它将被附加属性覆盖。您的视图模型可以保持不变。这是真正的魔法,是吧?
祝你好运!
I have a TaskStatus to Boolean converter that implements the IValueConverter interface in XAML for Windows Store Apps (universal apps).
I have three task states and I enabled the indeterminate state in a checkbox using IsThreeState="true".
Now although the IsChecked property seems to be a Boolean?, the converter always gets System.Boolean as target type. Whatever I return (null for example) always converts to false and therefore I can't get the third state in my checkbox.
Is there a way to either specify the TargetType in my converter or return a null so that IsChecked gets null as input and therefore shows the third state?
Here is the converter:
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-Code for the Checkbox
<CheckBox x:Name="CheckBoxTaskState" IsThreeState="True" IsChecked="{Binding Status, Converter={StaticResource TaskStatusToCheckBoxStateConverter}, Mode=TwoWay}"> </CheckBox>
解决方案According to [this][1]: Binding to nullable types in WinRT isn't supported at this time. How's that for an undocumented rule? Now you know.
Start with this
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)); } } }
And this
<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>
You can verify this error in your Output window. It reads something like this:
Error: Converter failed to convert value of type 'Boolean' to type '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').I am not pleased with this. So let's work around it with an attached property.
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; } }
Your XAML would only change like this:
<CheckBox Content="Hello three-state" IsThreeState="True" local:NullableCheckbox.Enabled="true" local:NullableCheckbox.IsChecked="{Binding State, Mode=TwoWay}" />
The regular IsChecked property doesn't matter, it will be overwritten by the attached property. Your viewmodel can stay the same. It's real magic, huh?
Best of luck!
这篇关于返回null布尔以复选框XAML状态转换器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!