ComboBox 最初不 select 绑定值
ComboBox does not select binding value initially
首先,不是重复的。
TextBox 和 CheckBox 可以正常工作,只是 ComboBox 不行。
型号
internal class Word : _Model
{
public enum Categories
{
Noun,
Verb,
}
private Categories category;
public Categories Category
{
get
{
return this.category;
}
set
{
this.SetProperty(ref this.category,
value);
}
}
}
通知(可以跳过阅读这部分)
internal abstract class _Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
控制(模型)
public sealed partial class WordEditor : UserControl
{
public WordEditor()
{
this.Model = new Models.Word();
this.Model.Category = Models.Word.Categories.Verb;
this.InitializeComponent();
}
private Models.Word Model { get; set; }
internal IList<KeyValuePair<Models.Word.Categories, string>> Categories { get { return new List<KeyValuePair<Models.Word.Categories, string>>() { new KeyValuePair<Models.Word.Categories, string>(Models.Word.Categories.Noun, "Noun"), new KeyValuePair<Models.Word.Categories, string>(Models.Word.Categories.Verb, "Verb") }; } }
}
绑定
<UserControl.Resources>
<converters:AnyConverter x:Key="AnyConverter"/>
</UserControl.Resources>
<StackPanel>
<ComboBox ItemsSource="{x:Bind Path=Categories, Mode=OneTime}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{x:Bind Path=Model.Category, Mode=TwoWay, Converter={StaticResource ResourceKey=AnyConverter}}"/>
</StackPanel>
转换器
internal class AnyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
问题
ComboBox 正确显示了 "Verb" 和 "Noun",模型正确反映了 "Verb" 或 "Noun" 上的选择。
但是,即使 Category 一开始就设置为 Verb,ComboBox 也没有显示。
如何修复它以便 ComboBox 在第一次出现时选择 "Verb"?
我重现了你的问题。这里的问题是 ComboBox.SelectedValue
不适用于枚举类型。为了测试这一点,我们可以使用不绑定的 ComboBox
并在代码隐藏中设置 SelectedValue
,如:
<ComboBox x:Name="cmb" DisplayMemberPath="Value" SelectedValuePath="Key" />
cmb.ItemsSource = Categories;
cmb.SelectedValue = Models.Word.Categories.Verb;
虽然我已经将Models.Word.Categories.Verb
设置为SelectedValue
,但它的值仍然是null
。
但是,当 Value
类型为 int
或 string
时有效。根据我的 WPF 经验,枚举类型也应该有效。我认为这可能是 UWP 中的一个错误。
作为变通方法,我认为您可以在 ComboBox 首次出现时使用 SelectedIndex
或 SelectedItem
属性 至 select "Verb"。例如:
在XAML中,使用SelectedIndex
代替SelectedValue
:
<ComboBox DisplayMemberPath="Value"
ItemsSource="{x:Bind Path=Categories, Mode=OneTime}"
SelectedIndex="{x:Bind Path=Model.Category, Mode=TwoWay, Converter={StaticResource ResourceKey=AnyConverter}}"
SelectedValuePath="Key" />
并将 Converter
更改为:
internal class AnyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (int)(Models.Word.Categories)value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return (Models.Word.Categories)(int)value;
}
}
在此之后,设置 this.Model.Category = Models.Word.Categories.Verb;
将起作用。
起初我认为@Jay Zuo - MSFT 是正确的,因为您必须将其转换为另一种形式(例如,int
);然而,通过使用 SelectedItem
,它起作用了!我像 OP 一样使用 SelectedValue
,但没有定义 SelectedValuePath
并且它不会 select 初始值。即使不定义 SelectedValuePath
也可以绑定到 SelectedItem
。
请注意,如果您绑定到 SelectedItem
而不是 SelectedIndex
,则完全不需要转换器。
我用 Windows 10 周年纪念版(10.0;内部版本 14393)对此进行了测试。
更新
事实证明我错了;p 为了更方便,我最终推出了自己的转换器。
public abstract class EnumToIntConverter<TEnum> : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Enum)
return (int)value;
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value is int)
return (TEnum)value;
return DependencyProperty.UnsetValue;
}
}
public sealed class MyEnumToIntConverter : EnumToIntConverter<MyEnum>
{
//Do nothing!
}
澄清一下,SelectedIndex
绝对 需要。
首先,不是重复的。
TextBox 和 CheckBox 可以正常工作,只是 ComboBox 不行。
型号
internal class Word : _Model
{
public enum Categories
{
Noun,
Verb,
}
private Categories category;
public Categories Category
{
get
{
return this.category;
}
set
{
this.SetProperty(ref this.category,
value);
}
}
}
通知(可以跳过阅读这部分)
internal abstract class _Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
控制(模型)
public sealed partial class WordEditor : UserControl
{
public WordEditor()
{
this.Model = new Models.Word();
this.Model.Category = Models.Word.Categories.Verb;
this.InitializeComponent();
}
private Models.Word Model { get; set; }
internal IList<KeyValuePair<Models.Word.Categories, string>> Categories { get { return new List<KeyValuePair<Models.Word.Categories, string>>() { new KeyValuePair<Models.Word.Categories, string>(Models.Word.Categories.Noun, "Noun"), new KeyValuePair<Models.Word.Categories, string>(Models.Word.Categories.Verb, "Verb") }; } }
}
绑定
<UserControl.Resources>
<converters:AnyConverter x:Key="AnyConverter"/>
</UserControl.Resources>
<StackPanel>
<ComboBox ItemsSource="{x:Bind Path=Categories, Mode=OneTime}"
DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{x:Bind Path=Model.Category, Mode=TwoWay, Converter={StaticResource ResourceKey=AnyConverter}}"/>
</StackPanel>
转换器
internal class AnyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
问题
ComboBox 正确显示了 "Verb" 和 "Noun",模型正确反映了 "Verb" 或 "Noun" 上的选择。
但是,即使 Category 一开始就设置为 Verb,ComboBox 也没有显示。
如何修复它以便 ComboBox 在第一次出现时选择 "Verb"?
我重现了你的问题。这里的问题是 ComboBox.SelectedValue
不适用于枚举类型。为了测试这一点,我们可以使用不绑定的 ComboBox
并在代码隐藏中设置 SelectedValue
,如:
<ComboBox x:Name="cmb" DisplayMemberPath="Value" SelectedValuePath="Key" />
cmb.ItemsSource = Categories;
cmb.SelectedValue = Models.Word.Categories.Verb;
虽然我已经将Models.Word.Categories.Verb
设置为SelectedValue
,但它的值仍然是null
。
但是,当 Value
类型为 int
或 string
时有效。根据我的 WPF 经验,枚举类型也应该有效。我认为这可能是 UWP 中的一个错误。
作为变通方法,我认为您可以在 ComboBox 首次出现时使用 SelectedIndex
或 SelectedItem
属性 至 select "Verb"。例如:
在XAML中,使用SelectedIndex
代替SelectedValue
:
<ComboBox DisplayMemberPath="Value"
ItemsSource="{x:Bind Path=Categories, Mode=OneTime}"
SelectedIndex="{x:Bind Path=Model.Category, Mode=TwoWay, Converter={StaticResource ResourceKey=AnyConverter}}"
SelectedValuePath="Key" />
并将 Converter
更改为:
internal class AnyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (int)(Models.Word.Categories)value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return (Models.Word.Categories)(int)value;
}
}
在此之后,设置 this.Model.Category = Models.Word.Categories.Verb;
将起作用。
起初我认为@Jay Zuo - MSFT 是正确的,因为您必须将其转换为另一种形式(例如,int
);然而,通过使用 SelectedItem
,它起作用了!我像 OP 一样使用 SelectedValue
,但没有定义 SelectedValuePath
并且它不会 select 初始值。即使不定义 SelectedValuePath
也可以绑定到 SelectedItem
。
请注意,如果您绑定到 SelectedItem
而不是 SelectedIndex
,则完全不需要转换器。
我用 Windows 10 周年纪念版(10.0;内部版本 14393)对此进行了测试。
更新
事实证明我错了;p 为了更方便,我最终推出了自己的转换器。
public abstract class EnumToIntConverter<TEnum> : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Enum)
return (int)value;
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (value is int)
return (TEnum)value;
return DependencyProperty.UnsetValue;
}
}
public sealed class MyEnumToIntConverter : EnumToIntConverter<MyEnum>
{
//Do nothing!
}
澄清一下,SelectedIndex
绝对 需要。