问题
First of all, not a duplicate.
TextBox and CheckBox work correctly, just not ComboBox.
Model
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);
}
}
}
Notify (safe to skip reading this part)
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));
}
}
}
Control (Model)
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") }; } }
}
Binding
<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>
Converter
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;
}
}
Issue
The ComboBox has "Verb" and "Noun" displayed correctly, and selection on "Verb" or "Noun" is reflected by the model correctly.
However, even though Category is set to Verb at the very first place, the ComboBox does not show that.
How to fix it so that the ComboBox selects "Verb" when it first appears?
回答1:
I reproduced your issue. The problem here is ComboBox.SelectedValue
doesn't work with enumeration type. To test this, we can use a ComboBox
without binding and set the SelectedValue
in code-behind like:
<ComboBox x:Name="cmb" DisplayMemberPath="Value" SelectedValuePath="Key" />
cmb.ItemsSource = Categories;
cmb.SelectedValue = Models.Word.Categories.Verb;
Although I've set Models.Word.Categories.Verb
to SelectedValue
, but its value still be null
.
However, it works when the Value
type is int
or string
. From my WPF experience, enumeration type should also work. I think this may be a bug in UWP.
As a workaround, I think you can use SelectedIndex
or SelectedItem
property to select "Verb" when the ComboBox first appears. For example:
In the XAML, use SelectedIndex
instead of 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" />
And change the Converter
like:
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;
}
}
After this, setting this.Model.Category = Models.Word.Categories.Verb;
will work.
回答2:
At first I thought @Jay Zuo - MSFT was right in that you'd have to convert it to another form (e.g., int
); however, by using SelectedItem
, it works! I was using SelectedValue
like OP, but didn't define SelectedValuePath
and it wouldn't select the initial value. Binding to SelectedItem
does even without defining SelectedValuePath
.
Note, if you bind to SelectedItem
versus SelectedIndex
, there's no need whatsoever for a converter.
I tested this with Windows 10 Anniversary Edition (10.0; Build 14393).
Update
Turns out I was wrong ;p I ended up rolling out my own converter for more convenience.
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!
}
To clarify, SelectedIndex
is absolutely needed.
来源:https://stackoverflow.com/questions/35599479/combobox-does-not-select-binding-value-initially