【问题标题】:Bound Silverlight Combobox not showing default value with EnumBinder绑定 Silverlight 组合框未使用 EnumBinder 显示默认值
【发布时间】:2011-11-21 05:31:49
【问题描述】:

我的模型使用枚举进行固定的多项选择。我正在使用位于 http://deanchalk.me.uk/post/Enumeration-Binding-In-Silverlight.aspx 的 Dean Chalk 的 EnumBinder 绑定到组合框。除了未显示默认值外,一切似乎都很好。选择的索引是-1,我绑定到SelectedItem还是SelectedValue都没关系。否则,组合框工作正常。我对任何其他绑定组合框的默认值都没有问题。

枚举绑定支持.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

/* All of this was once just part of the RichClient sub-namespace
 * but it has its uses elsewhere, so it has been moved. 
 */

/// <summary>
/// Container for enumeration values.
/// </summary>
/// <remarks>
/// http://deanchalk.me.uk/post/Enumeration-Binding-In-Silverlight.aspx
/// </remarks>
public sealed class EnumContainer
{
    public int EnumValue { get; set; }
    public string EnumDescription { get; set; }
    public object EnumOriginalValue { get; set; }
    public override string ToString() {
        return EnumDescription;
    }

    public override bool Equals(object obj) {
        if (obj == null)
            return false;
        if (obj is EnumContainer)
            return EnumValue.Equals((int)((EnumContainer)obj).EnumValue);
        return EnumValue.Equals((int)obj);
    }

    public override int GetHashCode() {
        return EnumValue.GetHashCode();
    }

}

/// <summary>
/// A collection to store a list of EnumContainers that hold enum values.
/// </summary>
/// <remarks>
/// http://deanchalk.me.uk/post/Enumeration-Binding-In-Silverlight.aspx
/// </remarks>
/// <typeparam name="T"></typeparam>
public class EnumCollection<T> : List<EnumContainer> where T : struct
{
    public EnumCollection() {
        var type = typeof(T);
        if (!type.IsEnum)
            throw new ArgumentException("This class only supports Enum types");
        var fields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public);
        foreach (var field in fields) {
            var container = new EnumContainer();
            container.EnumOriginalValue = field.GetValue(null);
            container.EnumValue = (int)field.GetValue(null);
            container.EnumDescription = field.Name;
            var atts = field.GetCustomAttributes(false);
            foreach (var att in atts)
                if (att is DescriptionAttribute) {
                    container.EnumDescription = ((DescriptionAttribute)att).Description;
                    break;
                }
            Add(container);
        }

    }
}

枚举值转换器.cs

using System;
using System.Globalization;
using System.Windows.Data;

/// <summary>
/// Supports two-way binding of enumerations.
/// </summary>
public class EnumValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                            CultureInfo culture) {
        return (int)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
                            CultureInfo culture) {
        if (value == null)
            return null;
        if (value.GetType() == targetType)
            return value;
        return ((EnumContainer)value).EnumOriginalValue;
    }
}

使用的枚举:

/// <summary>
/// Describes the available sorting options.
/// </summary>
public enum PeopleSortOptionsEnum
{

    [Display(Order = 10)]
    [Description("First Name, Last Name")]
    FirstNameThenLastName,

    [Display(Order = 20)]
    [Description("Last Name, First Name")]
    LastNameThenFirstName,

    [Display(Order = 30)]
    Grade,

    [Display(Order = 40)]
    Gender,

    [Display(Order = 50)]
    Age
}

我的模型的属性:

    /// <summary>
    /// This is the list for the enumeration to bind to.
    /// </summary>
    public EnumCollection<PeopleSortOptionsEnum> AvailableSortOptions
    {
        get { return new EnumCollection<PeopleSortOptionsEnum>(); }
    }

XAML sn-p:

    <ComboBox ItemsSource="{Binding Path=AvailableSortOptions, Mode=OneWay}" SelectedValue="{Binding Path=Preferences.SortOrder, Mode=TwoWay, Converter={StaticResource EnumConverter}}" Grid.Column="1" Grid.Row="2" Height="32" Margin="48,31,0,0" x:Name="cboSort" VerticalAlignment="Top" />

Preferences.SortOrder 的类型为 PeopleSortOptionsEnum,转换器在我的 app.xaml 中作为所有枚举类型的转换器。

有人知道为什么它不会将索引设置为当前选择的值吗?我正准备在代码隐藏中抛出一些代码,将 selectedindex 设置为加载时当前选择的值,但想想就觉得很脏。

除了这个问题,它的效果非常好,感谢 Dean!

编辑添加 Preferences.SortOrder 代码:

public PeopleSortOptionsEnum SortOrder 
{ 
  get { return sortOrder; } 
  set 
  { 
    if (sortOrder != value) 
    { 
      sortOrder = value; 
      PropertyHasChanged("SortOrder"); 
    } 
  } 
}

【问题讨论】:

  • 首选项类是什么样的?
  • 这只是我的模型中包含的一个POCO类,它是一个属性包并实现了INotifyPropertyChanged。我在模型中有一个类的实例,它是一个单独的类,因此我可以轻松地将其序列化到存储中。
  • 好的,您至少可以发布 Preferences.SortOrder 代码吗?
  • public PeopleSortOptionsEnum SortOrder { get { return sortOrder; } set { if (sortOrder != value) { sortOrder = value; PropertyHasChanged("排序顺序"); } } }
  • 这只是一个标准属性。就像我之前说的,我对任何其他属性都没有问题,而且我很确定这是上面发布的代码或 SL 组合框的问题。

标签: silverlight xaml binding combobox enums


【解决方案1】:

问题在于枚举转换器类的 Convert 方法:

public object Convert(object value, Type targetType, object parameter,
                        CultureInfo culture) {
    return (int)value;
}

当组合框 SelectedItem 从 SortOrder 获取值时,它以枚举值返回,此转换器将其转换为 int。但是,组合框项是 EnumContainer 对象的集合,而不是整数。因此无法设置所选项目。

要解决此问题,您必须做两件事。首先更改您的组合框绑定并设置 SelectedValuePath:

<ComboBox ItemsSource="{Binding Path=AvailableSortOptions}" 
          SelectedValue="{Binding Path=SortOrder, Mode=TwoWay, Converter={StaticResource EnumConverter}}" 
          SelectedValuePath="EnumOriginalValue"/>

其次,您必须稍微修改转换器上的 Convert 方法:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
  return value;
}

一旦我进行了这两项更改,它就开始按预期工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2023-03-08
    • 2011-10-10
    • 2016-09-12
    相关资源
    最近更新 更多