2009-08-02 45 views
10

我一直在瘋狂地將一個ComboBox綁定到一個類的枚舉類型屬性,其中枚舉本身在同一個類中聲明。將ComboBox綁定到嵌套在類中的枚舉

我想要按照此處提供的答案(wpf combobox binding to enum what i did wrong?)具體而言,我使用的是建議的MarkupExtension代碼和匹配的xaml代碼。

我的工作代碼爲:

定義枚舉在一個單獨的文件。使用枚舉

namespace EnumTest 
{ 
    public enum TestEnum {one, two, three, four }; 
} 

類(注意的PropertyChanged代碼已被刪除,以簡化的東西):

namespace EnumTest 
{ 
    public partial class Window1 : Window 
    { 
     Test _oTest = new Test(); 

     public Window1() 
     { 
      InitializeComponent(); 
      cmbBox.DataContext = _oTest; 
     } 
    } 
} 

擴展方法爲:使用類

namespace EnumTest 
{ 
    public class Test : INotifyPropertyChanged 
    { 
     private TestEnum _MyVar; 
     public TestEnum MyVar { 
      get { return _MyVar; } 
      set 
      { 
       _MyVar = value; 
       OnPropertyChanged("MyVar"); 
      } 
     } 

     public Test() 
     { 
      _MyVar = TestEnum.three; 
     } 
    } 
} 

程序文件顯示枚舉

namespace EnumTest 
{ 
    [MarkupExtensionReturnType(typeof(object[]))] 
    public class EnumValuesExtension : MarkupExtension 
    { 
     public EnumValuesExtension() 
     { 
     } 

     public EnumValuesExtension(Type enumType) 
     { 
      this.EnumType = enumType; 
     } 

     [ConstructorArgument("enumType")] 
     public Type EnumType { get; set; } 

     public override object ProvideValue(IServiceProvider serviceProvider) 
     { 
      if (this.EnumType == null) 
       throw new ArgumentException("The enum type is not set"); 
      return Enum.GetValues(this.EnumType); 
     } 
    } 
} 

和用於顯示數據的XAML代碼:

<Window x:Class="EnumTest.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:w="clr-namespace:EnumTest" 
    Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <ComboBox Name="cmbBox" 
        Height="20" 
        Width="80" 
        ItemsSource="{Binding Source={w:EnumValues EnumType=w:TestEnum}}" 
        SelectedItem="{Binding Path=MyVar}" 
        /> 
    </Grid> 
</Window> 

以上是所有良好和花花公子,但我想從在被定義定義枚舉 Test類和溝枚舉全球範圍。像這樣:

namespace EnumTest 
{ 
    public class Test : INotifyPropertyChanged 
    { 
     // Declare Enum **INSIDE** the class 
     public enum TestEnum {one, two, three, four }; 
     private TestEnum _MyVar; 
     public TestEnum MyVar { 
      get { return _MyVar; } 
      set 
      { 
       _MyVar = value; 
       OnPropertyChanged("MyVar"); 
      } 
     } 

     public Test() 
     { 
      _MyVar = TestEnum.three; 
     } 
    } 
} 

的SO問題我提到暗指匹配XAML語法之中:

 <ComboBox Name="cmbBox" 
        ... 
        ItemsSource="{Binding Source={w:EnumValues EnumType=w:Test+TestEnum}}" 
        ... 
        /> 

但是這(在某種程度上)並不爲我工作。當我做一個乾淨的構建,我得到一個「構建成功」的VS 2008狀態欄上的消息,但我也得被報道在XAML

Type 'Test+TestEnum' was not found. 

一個錯誤,但運行正常的代碼!

但是這意味着xaml設計器不會加載。所以我有點在做任何更多的WPF工作,直到我可以清除xaml錯誤。

我現在想知道這是VS 2008 SP1問題,而不是我的問題。

編輯

  1. 使我的問題的陳述更加明確。
  2. 試圖喬爾的第一個解決方案,但我結束了運行 2 XAML錯誤
  3. 試圖喬爾的第2個解決方案的代碼和工作開箱的 - 所以我有一個去!

注意 的SO問題,我得到的MarkupExtension代碼使用語法的這種風格的XAML:

<ComboBox ItemsSource="{w:EnumValues w:TestEnum}"/> 

當我使用,我得到一個編譯錯誤說沒有EnumValues構造函數需要1個參數。我做了一些谷歌搜索,這似乎是VS中的錯誤。我正在使用VS 2008 SP1。我確實看到一些評論,暗示它在VS 2010測試版中。無論如何,這就是爲什麼我使用xaml語法的原因:

<ComboBox ItemsSource="{w:EnumValues EnumType=w:TestEnum}"/> 

該語法的工作原理!

+0

關於構造函數的錯誤,它只發生在設計器中。否則它應該工作正常。爲了避免這個錯誤,在一個單獨的程序集中定義標記擴展 – 2009-08-03 13:16:28

+0

@Thomas:我忘記了設計者如何在何時何地構建類型以及如何實例化它們。 – 2009-08-03 14:41:57

+0

@Joel - 和新手wpf程序員知道這種事情怎麼樣?知道把一個類放在一個單獨的程序集中以滿足構建工具的一部分是比較模糊的恕我直言。但是我會繼續在這方面嘔心瀝血,直到我得到合理的理解。再次感謝。 – 2009-08-03 14:56:36

回答

3

獲取枚舉值用作數據源的另一種方式:

<Window.Resources> 
    <ObjectDataProvider 
     MethodName="GetValues" 
     ObjectType="{x:Type sys:Enum}" 
     x:Key="TestValues"> 
     <ObjectDataProvider.MethodParameters> 
      <w:Type2 
       TypeName="w:Test+TestEnum" /> 
     </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 
</Window.Resources> 

... 

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

請注意,您仍然需要Type2Extension因爲TypeExtension和嵌套類型古怪的。但是你不需要額外的自定義標記擴展。如果您在多個位置使用列表,這種方式會更好,因爲您可以在App.xaml資源中聲明它。

1

如何使用 x:Type標記擴展?

{w:EnumValues EnumType={x:Type w:Test+TestEnum}} 

除了實施INotifyPropertyChanged,我正好抄了你的代碼。我得到了你得到的錯誤,但它似乎運行得很好。儘管如此,不能加載設計師卻非常煩人。我試過的東西都沒有解決這個問題。

我在MSDN上找到了關於嵌套類型的this page,並且該線程中的一個建議是用於解析嵌套類型名稱的自定義MarkupExtension。我試圖讓它工作,但迄今沒有運氣。有時我在Type2Extension上遇到類似的錯誤,並且我得到了「枚舉類型未設置」以及其他調整。

啊哈!原作者如何調用GetType()存在一個錯誤!這裏的修正Type2Extension和我是如何使用它:

public class Type2Extension : System.Windows.Markup.TypeExtension { 
    public Type2Extension() { 
    } 

    public Type2Extension(string typeName) { 
     base.TypeName = typeName; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) { 
     IXamlTypeResolver typeResolver = (IXamlTypeResolver) serviceProvider.GetService(typeof(IXamlTypeResolver)); 
     int sepindex = TypeName.IndexOf('+'); 
     if (sepindex < 0) 
      return typeResolver.Resolve(TypeName); 
     else { 
      Type outerType = typeResolver.Resolve(TypeName.Substring(0, sepindex)); 
      return outerType.Assembly.GetType(outerType.FullName + "+" + TypeName.Substring(sepindex + 1)); 
     } 
    } 
} 

和XAML:

ItemsSource="{Binding Source={w:EnumValues {w:Type2 w:Test+TestEnum}}}" 

這似乎是做工精細的設計負荷。我會將Type2Extension加入我自己的小圖書館。

編輯:奇怪的是,如果我改變了在EnumValues

if (this.EnumType == null) 
    throw new ArgumentException("The enum type is not set"); 

要這樣:

if (this.EnumType == null) 
    return null; 

那麼那些構造錯誤消失。那是我改變的另一件事。不過,我很快會發佈一個獲取枚舉值的替代方法。