ডাব্লুপিএফ-এর একটি কম্বোবক্স নিয়ন্ত্রণে একটি এনামকে কীভাবে বাঁধবেন?


182

আমি এনামগুলিকে যেমন দেখানো হয়েছে সেখানে একটি সাধারণ উদাহরণ সন্ধানের চেষ্টা করছি। আমি যে সমস্ত উদাহরণ দেখেছি সেগুলি দেখতে সুন্দর দেখানোর স্ট্রিং যুক্ত করার চেষ্টা করেছে তবে আমি সেই জটিলতাটি চাই না।

মূলত আমার কাছে একটি ক্লাস রয়েছে যা আমি আবদ্ধ সমস্ত বৈশিষ্ট্য ধারণ করে, প্রথমে এই ক্লাসে ডেটা কনটেক্সট সেট করে এবং তারপরে xaml ফাইলে এই জাতীয় বাঁধাই নির্দিষ্ট করে:

<ComboBox ItemsSource="{Binding Path=EffectStyle}"/>

তবে এটি ComboBoxআইটেম হিসাবে এনাম মানগুলি দেখায় না ।


9
আপনি যা খুঁজছেন তা এখানে: ডাব্লুপিএফ অবজেক্টডেটাপ্রোভাডার - কম্বোবক্সে এনামকে আবদ্ধ করা আপনি সেখান থেকে সম্পূর্ণ উত্স কোড উদাহরণও ডাউনলোড করতে পারেন।

আমার মতে সেরা উত্তরটি হ'ল: স্ট্যাকওভারফ্লো.com
গিম্পি

উত্তর:


306

আপনি উইন্ডো Loadedইভেন্ট হ্যান্ডলারে নিম্নলিখিত কোডটি রেখে কোড থেকে এটি করতে পারেন , উদাহরণস্বরূপ:

yourComboBox.ItemsSource = Enum.GetValues(typeof(EffectStyle)).Cast<EffectStyle>();

আপনার যদি এটি XAML এ আবদ্ধ করতে হয় তবে আপনাকে ObjectDataProviderবাধ্যতামূলক উত্স হিসাবে উপলব্ধ অবজেক্ট তৈরি করতে ব্যবহার করতে হবে:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:StyleAlias="clr-namespace:Motion.VideoEffects">
    <Window.Resources>
        <ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
                            ObjectType="{x:Type System:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="StyleAlias:EffectStyle"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    <Grid>
        <ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
                  SelectedItem="{Binding Path=CurrentEffectStyle}" />
    </Grid>
</Window>

পরবর্তী কোডের প্রতি দৃষ্টি আকর্ষণ করুন:

xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:StyleAlias="clr-namespace:Motion.VideoEffects"

নেমস্পেস এবং সমাবেশের মানচিত্র কীভাবে আপনি এমএসডিএন এ পড়তে পারেন তা গাইড করুন ।


1
প্রথম লিঙ্ক থেকে পরীক্ষিত উদাহরণ, ঠিক আছে কাজ করে। যুক্ত উত্তর এবং আমার উত্তরে মন্তব্য দেখুন।
কিরিলো এম

1
এমএসডিএন ফোরামগুলিতে আপনার সমস্যাটি খুঁজে পেয়েছে ( social.msdn.microsoft.com/forums/en/wpf/thread/… )। প্রকল্পটি পরিষ্কার এবং পুনর্নির্মাণের চেষ্টা করুন। সম্ভবত আপনার অন্য একটি প্রশ্নে এই সমস্যাটি জিজ্ঞাসা করা উচিত। এটিই কেবল আমি পরামর্শ করতে পারি ... যাইহোক, প্রদর্শিত উদাহরণটি সঠিক।
কিরিলো এম

1
ধন্যবাদ, এটি উদ্ভট তবে আমি ডাব্লুপিএফ পাগলের সাথে একই রকম জিনিস দেখেছি। করবে এবং আপনাকে জানাবে। বিটিডব্লিউই
জোয়ান

2
আপনার এটিতে রেফারেন্স যুক্ত করতে এবং xmlns:DllAlias="clr-namespace:NamespaceInsideDll; assembly=DllAssemblyName"এটি ব্যবহার করতে এক্সএএমএলএল যুক্ত করা দরকার। এখানে গাইড রয়েছে: এমএসডিএন.মাইক্রোসফটকম /en-us/library/ms747086.aspx
ক্যারিলো এম

4
আপনি রিশার্পারের মতো এই জাতীয় সরঞ্জাম ব্যবহার করতে পারেন। এটি সমস্ত রেফারেন্স অ্যাসেম্বলিকে পার্স করে এবং কী কী অন্তর্ভুক্ত করা উচিত তা পরামর্শ দেয়। লেখার দরকার নেই - কেবল অপশনগুলি থেকে নির্বাচন করুন।
কিরিলো এম

116

আমি আমার কাছে সংজ্ঞায়িত করা বাধ্যতামূলক সমস্ত বস্তুর জন্য পছন্দ করি ViewModelতাই আমি <ObjectDataProvider>যখন সম্ভব হয় তখন xaml এ ব্যবহার এড়াতে চেষ্টা করি ।

আমার সমাধানটি ভিউতে সংজ্ঞায়িত কোনও ডেটা এবং কোনও কোড-পিছনে ব্যবহার করে না। কেবলমাত্র একটি ডাটাবাইন্ডিং, একটি পুনরায় ব্যবহারযোগ্য ভ্যালু কনভার্টার, কোনও এনুম প্রকারের জন্য বিবরণ সংগ্রহের একটি পদ্ধতি এবং এর সাথে বাঁধতে ভিউমোডেলে একক সম্পত্তি।

যখন আমি একটি বাঁধাই করার চান Enumএকটি থেকে ComboBoxটেক্সট আমি প্রদর্শন করতে চাই না মান সাথে মেলে Enum, তাই আমি ব্যবহার [Description()]অ্যাট্রিবিউট এটা যে টেক্সট আমি আসলে দেখতে চান দিতে ComboBox। আমার যদি সপ্তাহের বেশ কয়েকটি দিন থাকে তবে এটি দেখতে কিছুটা এমন দেখাবে:

public enum DayOfWeek
{
  // add an optional blank value for default/no selection
  [Description("")]
  NOT_SET = 0,
  [Description("Sunday")]
  SUNDAY,
  [Description("Monday")]
  MONDAY,
  ...
}

প্রথম আমি এনামগুলিকে মোকাবেলার জন্য কয়েকটি পদ্ধতি সহ সহায়ক শ্রেণি তৈরি করেছি। একটি পদ্ধতি একটি নির্দিষ্ট মানের জন্য একটি বিবরণ পায়, অন্য পদ্ধতিটি একটি মানের জন্য সমস্ত মান এবং তাদের বিবরণ পায়।

public static class EnumHelper
{
  public static string Description(this Enum value)
  {
    var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attributes.Any())
      return (attributes.First() as DescriptionAttribute).Description;

    // If no description is found, the least we can do is replace underscores with spaces
    // You can add your own custom default formatting logic here
    TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
    return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
  }

  public static IEnumerable<ValueDescription> GetAllValuesAndDescriptions(Type t)
  {
    if (!t.IsEnum)
      throw new ArgumentException($"{nameof(t)} must be an enum type");

    return Enum.GetValues(t).Cast<Enum>().Select((e) => new ValueDescription() { Value = e, Description = e.Description() }).ToList();
  }
}

এর পরে, আমরা একটি তৈরি করি ValueConverter। উত্তরাধিকার সূচনাটি MarkupExtensionএক্সএএমএল-তে ব্যবহার করা সহজ করে তোলে যাতে এটি এটিকে একটি উত্স হিসাবে ঘোষণা করতে হবে না।

[ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return EnumHelper.GetAllValuesAndDescriptions(value.GetType());
  }
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return null;
  }
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    return this;
  }
}

আমার ViewModelকেবলমাত্র 1 টি সম্পত্তি দরকার যা আমার এবং কম্বোবক্স Viewউভয়ের জন্য আবদ্ধ করতে পারে :SelectedValueItemsSource

private DayOfWeek dayOfWeek;

public DayOfWeek SelectedDay
{
  get { return dayOfWeek; }
  set
  {
    if (dayOfWeek != value)
    {
      dayOfWeek = value;
      OnPropertyChanged(nameof(SelectedDay));
    }
  }
}

এবং অবশেষে ComboBoxদর্শনটি বাঁধতে ( বাঁধাইয়ের ValueConverterমধ্যে ব্যবহার করে ItemsSource) ...

<ComboBox ItemsSource="{Binding Path=SelectedDay, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
          SelectedValuePath="Value"
          DisplayMemberPath="Description"
          SelectedValue="{Binding Path=SelectedDay}" />

এই সমাধানটি বাস্তবায়নের জন্য আপনাকে কেবল আমার EnumHelperক্লাস এবং EnumToCollectionConverterক্লাসের অনুলিপি করতে হবে । তারা যে কোনও এনামের সাথে কাজ করবে । এছাড়াও, আমি এটি এখানে অন্তর্ভুক্ত করিনি, তবে ValueDescriptionক্লাসটি কেবল একটি সরল শ্রেণি যেখানে 2 টি পাবলিক অবজেক্ট বৈশিষ্ট্য রয়েছে, যাকে বলা হয় Value, বলা হয় Description। আপনি নিজে তৈরি করতে পারেন বা আপনি কোড ব্যবহার করতে একটি Tuple<object, object>বা ব্যবহার করতে পারেনKeyValuePair<object, object>


9
এই কাজটি করার জন্য, আমাকে একটি ValueDescriptionক্লাস তৈরি করতে হয়েছিল যার সর্বজনীন সম্পত্তি রয়েছে ValueএবংDescription
পার্চিক

4
হ্যাঁ, আপনি ক্লাসের পরিবর্তে Tuple<T1, T2>বা এর KeyValuePair<TKey, TValue>পরিবর্তে এই কোডটি পরিবর্তন করতে পারেন ValueDescriptionএবং তারপরে আপনাকে নিজের তৈরি করতে হবে না।
নিক

আমার কেবলমাত্র সিলেক্টক্লাস নয়, উভয় ভিউমোডাল বৈশিষ্ট্যের জন্য অনপ্রোপার্টি চেঞ্জড (বা সমতুল্য) প্রয়োগ করতে হবে।
উইল

তালিকাটি ফেরত দেওয়া সম্পত্তিটির জন্য আপনার অনপোপার্টিচেন্জ প্রয়োগ করা উচিত নয়। তালিকাটি এনুমের মান থেকে তৈরি করা হয়। রান চলাকালীন সময়ে এটি কখনই বদলাবে না এবং কখনই পরিবর্তন হয় না, এটি পরিবর্তিত হয়েছে তা কাউকে জানাতে হবে না। এছাড়াও, আপডেট করা সংস্করণ সহ, তালিকার সম্পত্তিটির এমনকি প্রয়োজন হয় না।
নিক

কম্বোবক্সের আইটেমসোর্স এবং নির্বাচিত মূল্য একই সম্পত্তি ue আইটেমসোর্সের তালিকা হওয়ার দরকার নেই? ওহ, আমি দেখতে পাচ্ছি, এটি এনামহেল্পার বস্তুগুলির একটি তালিকা তৈরি করে। এটি আসলে আমার ভিউমোডেলটিকে আরও সহজ করে তোলে যেহেতু আইটেমসোর্সটি পপুলেট করার জন্য আমার কোনও পৃথক অবজেক্টের তালিকা বজায় রাখতে হবে না।
স্টিলথ রাব্বি

46

আমি মার্কআপ এক্সটেনশন ব্যবহার করে আরেকটি সমাধান ব্যবহার করেছি।

  1. আমি ক্লাস তৈরি করেছি যা আইটেমগুলির উত্স সরবরাহ করে:

    public class EnumToItemsSource : MarkupExtension
    {
        private readonly Type _type;
    
        public EnumToItemsSource(Type type)
        {
            _type = type;
        }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return Enum.GetValues(_type)
                .Cast<object>()
                .Select(e => new { Value = (int)e, DisplayName = e.ToString() });
        }
    }
  2. এটি প্রায় সমস্ত ... এখন এটি এক্সএএমএল এ ব্যবহার করুন:

        <ComboBox DisplayMemberPath="DisplayName"
              ItemsSource="{persons:EnumToItemsSource {x:Type enums:States}}"
              SelectedValue="{Binding Path=WhereEverYouWant}"
              SelectedValuePath="Value" />
  3. আপনার এনামে 'এনামস: স্টেটস' পরিবর্তন করুন


1
@ নিক: স্বীকৃত উত্তরটি এক্সএএমএল-তে এনাম (বা আপনি যেমন মডেল বলেছেন) রেফারেন্স করছে। আপনার সমাধানটি ভিউ মডেলে 2 টি বৈশিষ্ট্য এবং ব্যাকিং ফিল্ড তৈরি করছে যা আমি পছন্দ করি না (ডিআরওয়াই নিয়ম)। এবং অবশ্যই, আপনাকে e.ToString()প্রদর্শনের নামের জন্য ব্যবহার করতে হবে না । আপনি আপনার নিজস্ব অনুবাদক, বর্ণনামূলক বৈশিষ্ট্য পার্সার, যাই হোক না কেন ব্যবহার করতে পারেন।
tom.maruska

2
@ tom.maruska আমি আপনার উত্তর বনাম আমার উত্তর পেতে চেষ্টা করছি না, তবে যেহেতু আপনি এটি উত্থাপন করেছেন, 2 টি সম্পত্তি থাকার সাথে তারা ডিআইআর বিধি লঙ্ঘন করে না যখন তারা 2 টি পৃথক বৈশিষ্ট্য যা বিভিন্ন উদ্দেশ্যে কাজ করে। এবং আপনার উত্তরের জন্য একটি সম্পত্তি যুক্ত করাও প্রয়োজন (এমনকি আপনি এই সম্পত্তিটি নিজেরাই বলেছিলেন {Binding Path=WhereEverYouWant}) এবং আপনি যদি এটি 2-উপায় বাইন্ডিং সমর্থন করতে চান তবে এটির জন্যও আপনার একটি সমর্থন ক্ষেত্র রয়েছে। সুতরাং আপনি এটি করে 2 টি সম্পত্তি এবং 1 ব্যাকিং ফিল্ড প্রতিস্থাপন করছেন না, আপনি কেবলমাত্র 1 টি একক-লাইন পঠনযোগ্য সম্পত্তি প্রতিস্থাপন করছেন।
নিক

@ নিক হ্যাঁ, আপনি সেই সম্পত্তি এবং ব্যাকিং ফিল্ড সম্পর্কে ঠিক বলেছেন :)
tom.maruska

24

অবজেক্টডাটাপ্রোভাইডার ব্যবহার করুন:

<ObjectDataProvider x:Key="enumValues"
   MethodName="GetValues" ObjectType="{x:Type System:Enum}">
      <ObjectDataProvider.MethodParameters>
           <x:Type TypeName="local:ExampleEnum"/>
      </ObjectDataProvider.MethodParameters>
 </ObjectDataProvider>

এবং তারপরে স্থিতিশীল সংস্থানকে আবদ্ধ করুন:

ItemsSource="{Binding Source={StaticResource enumValues}}"

এই নিবন্ধের উপর ভিত্তি করে


4
পুরোপুরি সহজ সমাধান। কিরমিরের উত্তরের মতো সিস্টেমের নামকরণ:xmlns:System="clr-namespace:System;assembly=mscorlib"
জোনাথন টোয়েট

ভিজ্যুয়াল স্টুডিও 2017 এর
ডব্লিউপিএফ

10

নিকের উত্তরটি আমাকে সত্যিই সাহায্য করেছে, তবে আমি বুঝতে পেরেছিলাম যে এটি একটি অতিরিক্ত ক্লাস, ভ্যালুডেস্ক্রিপশন এড়াতে সামান্য টুইট করা যেতে পারে। আমার মনে আছে যে ফ্রেমওয়ার্কটিতে ইতিমধ্যে একটি কীভ্যালিউপায়ার ক্লাস রয়েছে, সুতরাং এটি পরিবর্তে ব্যবহার করা যেতে পারে।

কোডটি কেবল সামান্য পরিবর্তিত হয়:

public static IEnumerable<KeyValuePair<string, string>> GetAllValuesAndDescriptions<TEnum>() where TEnum : struct, IConvertible, IComparable, IFormattable
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new ArgumentException("TEnum must be an Enumeration type");
        }

        return from e in Enum.GetValues(typeof(TEnum)).Cast<Enum>()
               select new KeyValuePair<string, string>(e.ToString(),  e.Description());
    }


public IEnumerable<KeyValuePair<string, string>> PlayerClassList
{
   get
   {
       return EnumHelper.GetAllValuesAndDescriptions<PlayerClass>();
   }
}

এবং অবশেষে এক্সএএমএল:

<ComboBox ItemSource="{Binding Path=PlayerClassList}"
          DisplayMemberPath="Value"
          SelectedValuePath="Key"
          SelectedValue="{Binding Path=SelectedClass}" />

আমি আশা করি এটি অন্যদের জন্য সহায়ক।


আমার প্রথম প্রয়োগটি একটি ব্যবহার KeyValuePairকরেছিল তবে শেষ পর্যন্ত আমি সিদ্ধান্ত নিয়েছিলাম KeyValuePairএমন কিছু উপস্থাপনের জন্য যা কোনও মূল-মূল্য জুড়ি নয় কেবল তুচ্ছ-সহজ সরল শ্রেণীর লেখা এড়াতে বোঝায় না। ValueDescriptionবর্গ মাত্র 5 লাইন, এবং তাদের মধ্যে 2 ন্যায়পূর্ণ {এবং}
নিক

8

আপনাকে এনামে মানগুলির একটি অ্যারে তৈরি করতে হবে যা সিস্টেম.ইনুম.গ্যাটভ্যালু () কল করে তৈরি করা যেতে পারে , এটি Typeআপনাকে যে এনামের আইটেমগুলি চান তা পাস করে ।

আপনি যদি ItemsSourceসম্পত্তিটির জন্য এটি নির্দিষ্ট করে থাকেন তবে তা এনামের সমস্ত মান সহ পপুলেশন করা উচিত। আপনি সম্ভবত এটিকে আবদ্ধ SelectedItemকরতে চান EffectStyle(ধরে নেওয়া এটি একই এনামের একটি সম্পত্তি, এবং বর্তমান মান রয়েছে)।


ধন্যবাদ, আপনি কি কোডের প্রথম অংশটি দেখাতে পারেন? আমি নিশ্চিত নই যে এনামের মানগুলি অ্যারে হিসাবে কোথায় সঞ্চয় করবেন? এনাম সম্পত্তি অন্য শ্রেণিতে অবস্থিত। আমি কি এক্সএএমএলের অভ্যন্তরে এই getValues ​​পদক্ষেপটি করতে পারি?
জোয়ান ওয়েঙ্গেজ

4

উপরের সমস্ত পোস্ট একটি সাধারণ কৌশল মিস করেছে। আইটেমসোর্স স্বয়ংক্রিয়ভাবে কীভাবে পপুলেশন করা যায় তা সलेक्ट করা ওয়ালিউডের বাঁধন থেকে এটি সম্ভব যে যাতে আপনার এক্সএএমএল মার্কআপটি ন্যায়সঙ্গত হয়।

<Controls:EnumComboBox SelectedValue="{Binding Fool}"/>

উদাহরণস্বরূপ আমার ভিউমোডেলে আমার রয়েছে

public enum FoolEnum
    {
        AAA, BBB, CCC, DDD

    };


    FoolEnum _Fool;
    public FoolEnum Fool
    {
        get { return _Fool; }
        set { ValidateRaiseAndSetIfChanged(ref _Fool, value); }
    }

ValidateRaiseAndSetIfChanged আমার INPC হুক। আপনার ভিন্ন হতে পারে।

এনামকম্বোবক্সের প্রয়োগটি নিম্নরূপ: তবে প্রথমে আমার অঙ্কের স্ট্রিং এবং মানগুলি পেতে আমাকে একটু সাহায্যকারী দরকার

    public static List<Tuple<object, string, int>> EnumToList(Type t)
    {
        return Enum
            .GetValues(t)
            .Cast<object>()
            .Select(x=>Tuple.Create(x, x.ToString(), (int)x))
            .ToList();
    }

এবং প্রধান শ্রেণি (নোট আমি যখন ওয়েটএইনের মাধ্যমে সম্পত্তি পরিবর্তনগুলি হুক করার জন্য ReactiveUI ব্যবহার করছি)

using ReactiveUI;
using ReactiveUI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Documents;

namespace My.Controls
{
    public class EnumComboBox : System.Windows.Controls.ComboBox
    {
        static EnumComboBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(EnumComboBox), new FrameworkPropertyMetadata(typeof(EnumComboBox)));
        }

        protected override void OnInitialized( EventArgs e )
        {
            base.OnInitialized(e);

            this.WhenAnyValue(p => p.SelectedValue)
                .Where(p => p != null)
                .Select(o => o.GetType())
                .Where(t => t.IsEnum)
                .DistinctUntilChanged()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(FillItems);
        }

        private void FillItems(Type enumType)
        {
            List<KeyValuePair<object, string>> values = new List<KeyValuePair<object,string>>();

            foreach (var idx in EnumUtils.EnumToList(enumType))
            {
                values.Add(new KeyValuePair<object, string>(idx.Item1, idx.Item2));
            }

            this.ItemsSource = values.Select(o=>o.Key.ToString()).ToList();

            UpdateLayout();
            this.ItemsSource = values;
            this.DisplayMemberPath = "Value";
            this.SelectedValuePath = "Key";

        }
    }
}

জেনেরিকের ক্ষেত্রে আপনার স্টাইলটি সঠিকভাবে সেট করা দরকার X এক্সএএমএল বা আপনার বাক্সে কোনও কিছুই রেন্ডার হবে না এবং আপনি আপনার চুলগুলি বাইরে টেনে আনবেন।

<Style TargetType="{x:Type local:EnumComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}">
</Style>

এবং এটি হ'ল এটি স্পষ্টতই i18n সমর্থন বাড়ানো যেতে পারে তবে পোস্টটি আরও দীর্ঘায়িত করবে।


3

ইউনিভার্সাল অ্যাপ্লিকেশনগুলি কিছুটা আলাদাভাবে কাজ করছে বলে মনে হচ্ছে; এতে পূর্ণ বৈশিষ্ট্যযুক্ত এক্সএএমএল এর সমস্ত শক্তি নেই। আমার জন্য যা কাজ করেছে তা হ'ল:

  1. আমি enums হিসাবে এনাম মানগুলির একটি তালিকা তৈরি করেছি (স্ট্রিংগুলিতে বা পূর্ণসংখ্যায় রূপান্তরিত হয়নি) এবং কম্বোবক্স আইটেমসোর্সকে এতে আবদ্ধ করেছি
  2. তারপরে আমি আমার সর্বজনীন সম্পত্তিতে কম্বোবক্স আইটেমটিলেসেট করতে পারি যার প্রকারের প্রশ্নটি এনাম

কেবল মজাদার জন্য আমি এটিতে সহায়তা করার জন্য কিছুটা টেম্প্লেটেড ক্লাস বেত্রাঘাত করেছি এবং এটি এমএসডিএন নমুনা পৃষ্ঠাতে প্রকাশ করেছি । অতিরিক্ত বিটগুলি আমাকে এনামগুলির নামটি overচ্ছিকভাবে ওভাররাইড করতে দেয় এবং আমাকে কিছু এনামগুলিকে আড়াল করতে দেয়। আমার কোডটি নিক এর মতো (উপরে) এর মতো ভয়াবহ দেখাচ্ছে, যা আমার ইচ্ছা ছিল আমি আগে দেখেছি।

নমুনা চালানো;  এটি এনামের সাথে একাধিক দুটি বাইন্ডিং অন্তর্ভুক্ত করে


3

এই প্রশ্নের অনেক দুর্দান্ত উত্তর আছে এবং আমি নম্রভাবে আমার জমা দিন। আমি দেখতে পাই যে খনিটি কিছুটা সহজ এবং আরও মার্জিত। এটির জন্য কেবল একটি মান রূপান্তরকারী প্রয়োজন।

একটি এনাম দেওয়া হয়েছে ...

public enum ImageFormat
{
    [Description("Windows Bitmap")]
    BMP,
    [Description("Graphics Interchange Format")]
    GIF,
    [Description("Joint Photographic Experts Group Format")]
    JPG,
    [Description("Portable Network Graphics Format")]
    PNG,
    [Description("Tagged Image Format")]
    TIFF,
    [Description("Windows Media Photo Format")]
    WDP
}

এবং একটি মান রূপান্তরকারী ...

public class ImageFormatValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is ImageFormat format)
        {
            return GetString(format);
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string s)
        {
            return Enum.Parse(typeof(ImageFormat), s.Substring(0, s.IndexOf(':')));
        }
        return null;
    }

    public string[] Strings => GetStrings();

    public static string GetString(ImageFormat format)
    {
        return format.ToString() + ": " + GetDescription(format);
    }

    public static string GetDescription(ImageFormat format)
    {
        return format.GetType().GetMember(format.ToString())[0].GetCustomAttribute<DescriptionAttribute>().Description;

    }
    public static string[] GetStrings()
    {
        List<string> list = new List<string>();
        foreach (ImageFormat format in Enum.GetValues(typeof(ImageFormat)))
        {
            list.Add(GetString(format));
        }

        return list.ToArray();
    }
}

সম্পদ ...

    <local:ImageFormatValueConverter x:Key="ImageFormatValueConverter"/>

এক্সএএমএল ঘোষণা ...

    <ComboBox Grid.Row="9" ItemsSource="{Binding Source={StaticResource ImageFormatValueConverter}, Path=Strings}"
              SelectedItem="{Binding Format, Converter={StaticResource ImageFormatValueConverter}}"/>

মডেল দেখুন ...

    private ImageFormat _imageFormat = ImageFormat.JPG;
    public ImageFormat Format
    {
        get => _imageFormat;
        set
        {
            if (_imageFormat != value)
            {
                _imageFormat = value;
                OnPropertyChanged();
            }
        }
    }

কম্বোবক্সের ফলাফল ...

এনম্বের কাছে আবদ্ধ কম্বোবক্স


আমার জন্য, এটি প্রশ্নের সেরা সমাধান: সহজ, বোঝা সহজ, বাস্তবায়নের জন্য সোজা।
ইনফরমেশনিক

এই সমাধানটির সাথে সমস্যাটি হ'ল এটি অলোচ্য is
রবিন ডেভিস

@ রবিনড্যাভিস আপনি এটি স্থানীয় করতে পারেন। একটি কাস্টম বিবরণঅ্যাগ্রহকারীর প্রয়োজন যার মধ্যে আমি কয়েকটি তৈরি করেছি। : কিছু ধারনা এই তাই প্রশ্ন দেখতে পাবেন stackoverflow.com/questions/7398653/...
AQuirky

2
public class EnumItemsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!value.GetType().IsEnum)
            return false;

        var enumName = value.GetType();
        var obj = Enum.Parse(enumName, value.ToString());

        return System.Convert.ToInt32(obj);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Enum.ToObject(targetType, System.Convert.ToInt32(value));
    }
}

আপনি যদি এনজেক্ট মডেলের বৈশিষ্ট্যগুলির জন্য সরাসরি বাঁধাই করেন তবে রজারস এবং গ্রেগের উত্তরকে এ জাতীয় এনাম মান রূপান্তরকারী দিয়ে প্রসারিত করা উচিত।


1

যদি আপনি আপনার ভিউমোডেলের কোনও প্রকৃত এনাম সম্পত্তিকে বাধ্য করেন তবে কোনও এনামের উপস্থাপনা নয়, জিনিসগুলি জটিল হয়ে ওঠে। আমি খুঁজে পেয়েছি যে স্ট্রিং উপস্থাপনের সাথে আবদ্ধ হওয়া আবশ্যক, উপরের উদাহরণগুলির সমস্তটিতে যেমন প্রত্যাশা করা হয় তেমন মানটি নয়।

আপনি নিজের ভিউমোডেলটিতে যে সম্পত্তিতে বাঁধতে চান তার জন্য একটি সাধারণ পাঠ্যবাক্সকে আবদ্ধ করে আপনি যদি বলতে পারেন যে এটি ঘটেছে। যদি এটি পাঠ্য দেখায় তবে স্ট্রিংয়ের সাথে আবদ্ধ হন। যদি এটি একটি নম্বর দেখায়, মানকে বাঁধুন। দ্রষ্টব্য আমি ডিসপ্লে দু'বার ব্যবহার করেছি যা সাধারণত একটি ত্রুটি হতে পারে তবে এটি কেবলমাত্র এটি কাজ করে।

<ComboBox SelectedValue="{Binding ElementMap.EdiDataType, Mode=TwoWay}"
                      DisplayMemberPath="Display"
                      SelectedValuePath="Display"
                      ItemsSource="{Binding Source={core:EnumToItemsSource {x:Type edi:EdiDataType}}}" />

গ্রেগ


এই উত্তরটি অসম্পূর্ণ বলে মনে হচ্ছে: * / কোর / কী?
ট্র্যাপিকি

1

আমি টম.মারুস্কার উত্তরটি পছন্দ করেছি , তবে আমার টেমপ্লেটটি রানটাইমের সময় মুখোমুখি হতে পারে এমন কোনও এনামের সমর্থন করা দরকার। তার জন্য, আমাকে মার্কআপ এক্সটেনশনে টাইপ নির্দিষ্ট করতে একটি বাঁধাই ব্যবহার করতে হয়েছিল। আমি নিকোলে.নেইকিয়েনকো থেকে এই উত্তরটিতে কাজ করতে সক্ষম হয়েছি খুব নমনীয় মার্কআপ এক্সটেনশন নিয়ে এসেছি যা আমি ভাবতে পারি যে কোনও ক্ষেত্রে কাজ করবে। এটি এভাবে গ্রাস করা হয়:

<ComboBox SelectedValue="{Binding MyEnumProperty}" 
          SelectedValuePath="Value"
          ItemsSource="{local:EnumToObjectArray SourceEnum={Binding MyEnumProperty}}" 
          DisplayMemberPath="DisplayName" />

উপরে উল্লিখিত ছাঁটাই করা আপ আপ এক্সটেনশনের উত্স:

class EnumToObjectArray : MarkupExtension
{
    public BindingBase SourceEnum { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        DependencyObject targetObject;
        DependencyProperty targetProperty;

        if (target != null && target.TargetObject is DependencyObject && target.TargetProperty is DependencyProperty)
        {
            targetObject = (DependencyObject)target.TargetObject;
            targetProperty = (DependencyProperty)target.TargetProperty;
        }
        else
        {
            return this;
        }

        BindingOperations.SetBinding(targetObject, EnumToObjectArray.SourceEnumBindingSinkProperty, SourceEnum);

        var type = targetObject.GetValue(SourceEnumBindingSinkProperty).GetType();

        if (type.BaseType != typeof(System.Enum)) return this;

        return Enum.GetValues(type)
            .Cast<Enum>()
            .Select(e => new { Value=e, Name = e.ToString(), DisplayName = Description(e) });
    }

    private static DependencyProperty SourceEnumBindingSinkProperty = DependencyProperty.RegisterAttached("SourceEnumBindingSink", typeof(Enum)
                       , typeof(EnumToObjectArray), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

    /// <summary>
    /// Extension method which returns the string specified in the Description attribute, if any.  Oherwise, name is returned.
    /// </summary>
    /// <param name="value">The enum value.</param>
    /// <returns></returns>
    public static string Description(Enum value)
    {
        var attrs = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (attrs.Any())
            return (attrs.First() as DescriptionAttribute).Description;

        //Fallback
        return value.ToString().Replace("_", " ");
    }
}

1

সহজ এবং স্পষ্ট ব্যাখ্যা: http://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/

xmlns:local="clr-namespace:BindingEnums"
xmlns:sys="clr-namespace:System;assembly=mscorlib"

...

<Window.Resources>
    <ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
                        ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="local:Status"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

...

<Grid>
    <ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="150"
              ItemsSource="{Binding Source={StaticResource dataFromEnum}}"/>
</Grid>

0

ব্যবহার করে ReactiveUI, আমি নিম্নলিখিত বিকল্প সমাধান তৈরি করেছি। এটি একটি মার্জিত সর্ব-ও-সমাধান সমাধান নয়, তবে আমি মনে করি খুব কমপক্ষে এটি পাঠযোগ্য।

আমার ক্ষেত্রে, একটি তালিকাতে enumকোনও নিয়ন্ত্রণের তালিকা বাঁধাই বিরল ঘটনা, সুতরাং কোডের বেস জুড়ে সমাধানটি স্কেল করার দরকার নেই। তবে কোডটি একটিতে পরিবর্তন EffectStyleLookup.Itemকরে আরও জেনেরিক করা যায় Object। আমি এটি আমার কোড দিয়ে পরীক্ষা করেছি, অন্য কোনও পরিবর্তন দরকার নেই। যার অর্থ একটি সহায়ক শ্রেণি যে কোনও enumতালিকায় প্রয়োগ করা যেতে পারে । যদিও এটি তার পাঠযোগ্যতা হ্রাস করবে -ReactiveList<EnumLookupHelper> দুর্দান্ত রিং নেই।

নিম্নলিখিত সহায়ক শ্রেণীর ব্যবহার:

public class EffectStyleLookup
{
    public EffectStyle Item { get; set; }
    public string Display { get; set; }
}

ভিউমোডেলে, এনামগুলির তালিকা রূপান্তর করুন এবং এটিকে সম্পত্তি হিসাবে প্রকাশ করুন:

public ViewModel : ReactiveObject
{
  private ReactiveList<EffectStyleLookup> _effectStyles;
  public ReactiveList<EffectStyleLookup> EffectStyles
  {
    get { return _effectStyles; }
    set { this.RaiseAndSetIfChanged(ref _effectStyles, value); }
  }

  // See below for more on this
  private EffectStyle _selectedEffectStyle;
  public EffectStyle SelectedEffectStyle
  {
    get { return _selectedEffectStyle; }
    set { this.RaiseAndSetIfChanged(ref _selectedEffectStyle, value); }
  }

  public ViewModel() 
  {
    // Convert a list of enums into a ReactiveList
    var list = (IList<EffectStyle>)Enum.GetValues(typeof(EffectStyle))
      .Select( x => new EffectStyleLookup() { 
        Item = x, 
        Display = x.ToString()
      });

    EffectStyles = new ReactiveList<EffectStyle>( list );
  }
}

ইন ComboBox, কাজে লাগাতে SelectedValuePathমূল জুড়তে সম্পত্তি, enumমান:

<ComboBox Name="EffectStyle" DisplayMemberPath="Display" SelectedValuePath="Item" />

দেখুন, এই মূল জুড়তে অনুমতি পারবেন enumকরার SelectedEffectStyleViewModel, কিন্তু প্রদর্শন ToString()মান ComboBox:

this.WhenActivated( d =>
{
  d( this.OneWayBind(ViewModel, vm => vm.EffectStyles, v => v.EffectStyle.ItemsSource) );
  d( this.Bind(ViewModel, vm => vm.SelectedEffectStyle, v => v.EffectStyle.SelectedValue) );
});

আমি মনে করি আপনার ভিউমোডেলটিতে একটি ত্রুটি রয়েছে। 1) এটি এফেক্টসাইললুকআপের একটি প্রতিক্রিয়াশীল তালিকা হওয়া উচিত নয় ?, 2) আপনার প্রথমে একটি খালি রিঅ্যাকটিভলিস্ট <T> () করা উচিত। তারপরে আইটেম যুক্ত করুন। শেষ অবধি: রিঅ্যাকটিভলিস্ট <টি> এখন হ্রাস করা হয়েছে (তবে এখনও কাজ করে)। ইফেক্টস্টাইলস = নতুন রিঅ্যাকটিভলিস্ট <EffectStyleLookup> (); EffectStyles.AddRange (তালিকা); এটি দেখানোর জন্য সময় দেওয়ার জন্য ধন্যবাদ।
ব্যবহারকারী 1040323

0

আমি আমার মন্তব্য যুক্ত করছি (ভিসি-তে, দুঃখের সাথে, তবে ধারণাটি সহজেই হৃদস্পন্দনে সি # তে প্রতিলিপি করা যেতে পারে), কারণ আমার কেবল এটি উল্লেখ করা হয়েছিল এবং উত্তরগুলি খুব জটিল হওয়ায় এটির কোনও পছন্দ হয়নি। এটি এই কঠিন হতে হবে না।

তাই আমি একটি সহজ উপায় নিয়ে এসেছি। শনাক্তকারীকে একটি অভিধানে আবদ্ধ করুন। কম্বোবক্সে সেই অভিধানটি আবদ্ধ করুন।

আমার কম্বোবক্স:

<ComboBox x:Name="cmbRole" VerticalAlignment="Stretch" IsEditable="False" Padding="2" 
    Margin="0" FontSize="11" HorizontalAlignment="Stretch" TabIndex="104" 
    SelectedValuePath="Key" DisplayMemberPath="Value" />

আমার কোড পিছনে। আশা করি, এটি অন্য কাউকে সাহায্য করতে পারে।

Dim tDict As New Dictionary(Of Integer, String)
Dim types = [Enum].GetValues(GetType(Helper.Enumerators.AllowedType))
For Each x As Helper.Enumerators.AllowedType In types
    Dim z = x.ToString()
    Dim y = CInt(x)
    tDict.Add(y, z)
Next

cmbRole.ClearValue(ItemsControl.ItemsSourceProperty)
cmbRole.ItemsSource = tDict

কিরিলোর উত্তর আপনার চেয়ে অনেক সহজ - এটি কী জটিল তা আমি বুঝতে পারি না? তার কোডে শূন্য রূপান্তর প্রয়োজন।
জনাথন সুলিঙ্গার

আমি আমার সমস্ত যুক্তি XAML এর হাতে রাখতে চাইনি। আমি আমার যুক্তিটি আমার উপায়ে (সর্বদা সর্বোত্তম উপায় নয়) করতে পছন্দ করি তবে এটি কোথায় এবং কেন পরিকল্পনা অনুসারে কিছু যাচ্ছে না তা আমাকে বুঝতে দেয়। তাঁর জটিলতা কম, তবে যুক্তিটি করার জন্য এক্সএএমএল / ডাব্লুপিএফ এর উপর নির্ভর করে। আমি শুধু এর ভক্ত নই। বিড়ালের ত্বকের 10,000 টি উপায়, আপনি কি জানেন?
লাকি পোলাইটিস

যথেষ্ট ফর্সা। আমি ব্যক্তিগতভাবে আমার জন্য বাক্সের বাইরে তৈরি বৈশিষ্ট্যগুলি ব্যবহার করতে পছন্দ করি তবে এটি কেবল আমার পছন্দ;) সেখানে প্রত্যেকের নিজস্ব!
জনাথন সুলিঞ্জার

জী জনাব! আমি পুরোপুরি বুঝতে পেরেছি. ওয়েব ডেভলপমেন্ট থেকে আসা সফ্টওয়্যার বিকাশে আমাকে বাধ্য করা হয়েছে। আমি ডাব্লুপিএফ-তে আপ-টু-ডেট ছিলাম না এবং আমি যেভাবে এগিয়ে চলেছি তা শিখতে হবে। আমি এখনও ডাব্লুপিএফ / এক্সএএমএল নিয়ন্ত্রণের সমস্ত জটিলতা বুঝতে পারি না এবং তাই আমি কীভাবে জিনিসগুলি কাজ করতে আশা করব তার সমাধানের চেয়ে আরও বেশি হিক্কার খুঁজে পেয়েছি। তবে আমি এই কথোপকথনের প্রশংসা করি। এটি আমাকে আরও কিছু গবেষণা করতে বাধ্য করেছে।
লাকি পোলাইটিস

0

নিকের নির্জনতা আরও সরল করা যায়, অভিনব কোনও কিছুই না থাকলে আপনার কেবলমাত্র একক রূপান্তরকারী প্রয়োজন:

[ValueConversion(typeof(Enum), typeof(IEnumerable<Enum>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var r = Enum.GetValues(value.GetType());
        return r;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

তারপরে আপনি যেখানেই আপনার কম্বো বাক্সটি প্রদর্শিত হতে চান এটি ব্যবহার করুন:

<ComboBox ItemsSource="{Binding PagePosition, Converter={converter:EnumToCollectionConverter}, Mode=OneTime}"  SelectedItem="{Binding PagePosition}" />

0

আমি এটি হিসাবে এটি বাস্তবায়নের প্রস্তাব করব না তবে আশা করি এটি একটি ভাল সমাধান অনুপ্রাণিত করতে পারে।

ধরা যাক আপনার এনাম ফু। তাহলে আপনি এই জাতীয় কিছু করতে পারেন।

public class FooViewModel : ViewModel
{
    private int _fooValue;

    public int FooValue
    {
        get => _fooValue;
        set
        {
            _fooValue = value;
            OnPropertyChange();
            OnPropertyChange(nameof(Foo));
            OnPropertyChange(nameof(FooName));
        }
    }
    public Foo Foo 
    { 
        get => (Foo)FooValue; 
        set 
        { 
            _fooValue = (int)value;
            OnPropertyChange();
            OnPropertyChange(nameof(FooValue));
            OnPropertyChange(nameof(FooName));
        } 
    }
    public string FooName { get => Enum.GetName(typeof(Foo), Foo); }

    public FooViewModel(Foo foo)
    {
        Foo = foo;
    }
}

তারপরে Window.Loadপদ্ধতিতে আপনি সমস্ত এনামগুলিকে লোড করতে পারেন ObservableCollection<FooViewModel>যা আপনি কম্বোবক্সের ডেটা কনটেক্সট হিসাবে সেট করতে পারেন।


0

আমি কেবল এটি সহজ রেখেছি। আমি আমার ভিউমোডেলে এনাম মান সহ আইটেমগুলির একটি তালিকা তৈরি করেছি:

public enum InputsOutputsBoth
{
    Inputs,
    Outputs,
    Both
}

private IList<InputsOutputsBoth> _ioTypes = new List<InputsOutputsBoth>() 
{ 
    InputsOutputsBoth.Both, 
    InputsOutputsBoth.Inputs, 
    InputsOutputsBoth.Outputs 
};

public IEnumerable<InputsOutputsBoth> IoTypes
{
    get { return _ioTypes; }
    set { }
}

private InputsOutputsBoth _selectedIoType;

public InputsOutputsBoth SelectedIoType
{
    get { return _selectedIoType; }
    set
    {
        _selectedIoType = value;
        OnPropertyChanged("SelectedIoType");
        OnSelectionChanged();
    }
}

আমার এক্সএএমএল কোডে আমার কেবল এটি দরকার:

<ComboBox ItemsSource="{Binding IoTypes}" SelectedItem="{Binding SelectedIoType, Mode=TwoWay}">
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.