簡體   English   中英

將 UWP ComboBox ItemsSource 綁定到 Enum

[英]Bind UWP ComboBox ItemsSource to Enum

可以在 WPF 應用程序中使用ObjectDataProvider將枚舉的字符串值綁定到 ComboBox 的 ItemsSource,如本問題所示

但是,在 UWP 應用程序中使用類似的代碼段時,ff. 顯示錯誤消息:

“Windows 通用項目不支持 ObjectDataProvider。”

在 UWP 中是否有一個簡單的替代方法可以做到這一點?

下面是我的一個原型中的一個工作示例。

枚舉

public enum GetDetails
{
    test1,
    test2,
    test3,
    test4,
    test5
}

物品來源

var _enumval = Enum.GetValues(typeof(GetDetails)).Cast<GetDetails>();
cmbData.ItemsSource = _enumval.ToList();

這會將組合框綁定到枚舉值。

如果您嘗試通過 xaml 和 Bindings 設置 SelectedItem,請確保首先設置 ItemsSource!

示例:

<ComboBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}"/>

相信我,UWP 中的 ComboBox 和枚舉是個壞主意。 節省一些時間,不要在 UWP 中的組合框上使用枚舉。 花了幾個小時試圖讓它發揮作用。 您可以嘗試其他答案中提到的解決方案,但您將遇到的問題是,當 SelectedValue 綁定到枚舉時,不會觸發 propertychange。 所以我只是將它轉換為int。

您可以在 VM 中創建一個屬性並將枚舉 GetDetails 轉換為 int。

public int Details
{
  get { return (int)Model.Details; }
  set { Model.Details = (GetDetails)value; OnPropertyChanged();}
}

然后你可以使用 int 和 string 處理一個類的列表,不確定你是否可以使用 KeyValuePair

public class DetailItem
{
  public int Value {get;set;}
  public string Text {get;set;}
}

public IEnumerable<DetailItem> Items
{
  get { return GetItems(); }
}

public IEnumerable<DetailItem> GetItems()
{
   yield return new DetailItem() { Text = "Test #1", Value = (int)GetDetails.test1 }; 
   yield return new DetailItem() { Text = "Test #2", Value = (int)GetDetails.test2 }; 
   yield return new DetailItem() { Text = "Test #3", Value = (int)GetDetails.test3 }; 
   // ..something like that
}

然后在Xaml上

<Combobox ItemsSource="{Binding Items, UpdateSourceTrigger=PropertyChanged}"
 SelectedValue="{Binding Details, UpdateSourceTriggerPropertyChanged, Mode=TwoWay}"
 SelectedValuePath="Value" 
 DisplayMemberPath="Text" />

我知道這是一篇舊帖子,但是將組合框的 SelectedIndex 綁定到 enum 屬性並像這樣定義您的值轉換器,

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string v = value.ToString();
        string[] vs = Enum.GetNames(typeof(YourEnumType));
        int index = vs.IndexOf(v);
        if (index > -1)
            return index;
        return 0;
    }


    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        int index = (int)value;
        if (index > -1)
            return (YourEnumType)index;
        return YourEnumType.DefaultValue;
    }

這是我為 UWP 提供的最簡單和最通用的枚舉綁定方式。 也許這可以幫助某人,因為這很容易綁定和本地化。

/// <summary>
///     Helper class to bind an Enum type as an control's ItemsSource.
/// </summary>
/// <typeparam name="T"></typeparam>
public class EnumItemsSource<T> where T : struct, IConvertible
{
    public string FullTypeString { get; set; }
    public string Name { get; set; }
    public string LocalizedName { get; set; }
    public T Value { get; set; }

    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="name"></param>
    /// <param name="value"></param>
    /// <param name="fullString"></param>
    public EnumItemsSource(string name, T value, string fullTypeString)
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("EnumItemsSource only accept Enum type.");

        Name = name;
        Value = value;
        FullTypeString = fullTypeString;

        // Retrieve localized name
        LocalizedName = AppResource.GetResource(FullTypeString.Replace('.', '-'));
    }

    /// <summary>
    ///     Create a list of EnumItemsSource from an enum type.
    /// </summary>
    /// <returns></returns>
    public static List<EnumItemsSource<T>> ToList()
    {
        // Put to lists
        var namesList = Enum.GetNames(typeof(T));
        var valuesList = Enum.GetValues(typeof(T)).Cast<T>().ToList();

        // Create EnumItemsSource list
        var enumItemsSourceList = new List<EnumItemsSource<T>>();
        for (int i = 0; i < namesList.Length; i++)
            enumItemsSourceList.Add(new EnumItemsSource<T>(namesList[i], valuesList[i], $"{typeof(T).Name}.{namesList[i]}"));

        return enumItemsSourceList;
    }
}

在視圖模型中:

    public List<EnumItemsSource<AccountType>> AccountTypes
    {
        get => EnumItemsSource<AccountType>.ToList();
    }

在視圖中:

<ComboBox ItemsSource="{Binding AccountTypes}" DisplayMemberPath="LocalizedName" SelectedValuePath="Value" SelectedValue="{Binding Path=Account.Type, Mode=TwoWay}" />

帶有ItemSource到 Enum 的ComboBox ,也帶有SelectedItem 並可以選擇用自定義字符串(例如翻譯)替換枚舉的名稱。 尊重 MVVM 模式。

枚舉:

public enum ChannelMark
{
   Undefinned,Left, Right,Front, Back
}

視圖模型

private ChannelMark _ChannelMark = ChannelMark.Undefinned;

public ChannelMark ChannelMark
{
    get => _ChannelMark;
    set => Set(ref _ChannelMark, value);
}

private List<int> _ChannelMarksInts = Enum.GetValues(typeof(ChannelMark)).Cast<ChannelMark>().Cast<int>().ToList();

public List<int> ChannelMarksInts
{
    get => _ChannelMarksInts;
    set => Set(ref _ChannelMarksInts, value);
}

XAML

<ComboBox ItemsSource="{x:Bind ViewModel.ChannelMarksInts}"  SelectedItem="{x:Bind ViewModel.ChannelMark, Converter={StaticResource ChannelMarkToIntConverter}, Mode=TwoWay}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding  Converter={StaticResource IntToChannelMarkConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

轉換器:

switch ((ChannelMark)value)
{
    case ChannelMark.Undefinned:
        return "Undefinned mark";
    case ChannelMark.Left:
        //translation
        return Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView().GetString("ChannelMarkEnumLeft");
    case ChannelMark.Right:
        return "Right Channel";
    case ChannelMark.Front:
        return "Front Channel";
    case ChannelMark.Back:
        return "Back Channel";
    default:
        throw new NotImplementedException();
}



public class IntToChannelMarkConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language) => ((ChannelMark)value).ToString();
    public object ConvertBack(object value, Type targetType, object parameter, string language) => throw new NotImplementedException();
}

我使用 Karnaltas 答案是因為它支持使用 resx 文件輕松本地化。 但是我在雙向綁定和返回我的實體時遇到了麻煩。 我通過更改綁定以使用 SelectedIndex 並添加轉換器解決了這個問題。 這樣組合框也能正確地選擇初始狀態並顯示它。

ViewModel 與 Karnalta 的解決方案一樣。

在視圖中更改綁定:

<ComboBox ItemsSource="{Binding AccountTypes}" DisplayMemberPath="LocalizedName" SelectedIndex={x:Bind ViewModel.Account.Type, Mode=TwoWay, Converter={StaticResource EnumToIntConverer}" />

新轉換器:

public class EnumToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {           
        return (int)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {            
        return Enum.Parse(targetType, value.ToString());
    }
}

並且不要忘記在頁面/控件中添加轉換器:

<Grid.Resources>
    <ResourceDictionary>
        <converters:EnumToIntConverter x:Key="EnumToIntConverter" />
    </ResourceDictionary>
</Grid.Resources>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM