2009-08-02 3 views
10

Ich bin verrückt geworden, weil ich eine Combobox an eine enum typisierte Eigenschaft einer Klasse gebunden habe, wo die enum selbst in derselben Klasse deklariert ist.Eine ComboBox an ein enum verschachteln, das in einer Klasse verschachtelt ist

Ich versuche der hier angegebenen Antwort zu folgen (wpf combobox binding to enum what i did wrong?) Insbesondere verwende ich den vorgeschlagenen MarkupExtension-Code und den passenden Xaml-Code.

Mein Arbeitscode lautet:

in einer separaten Datei, die Enum definieren.

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

Klasse, die die Enum verwendet (Beachten Sie, dass das Property Code entfernt wurde, Dinge zu vereinfachen):

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; 
     } 
    } 
} 

Programmdatei, die die Klasse verwendet:

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

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

Erweiterungsmethode für Anzeige der Enum

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); 
     } 
    } 
} 

Und der XAML-Code, der die Daten verwendet wird angezeigt: Die obige

<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> 

ist alles gut und gut, aber ich möchte die Enum innerhalb die Test-Klasse definieren und die Enum Graben aus an die definiert ist globaler Geltungsbereich. Wie so:

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; 
     } 
    } 
} 

Die SO Frage, die ich an die entsprechenden XAML-Syntax als Wesen spielt bezeichnet:

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

Aber diese (Art) für mich nicht funktioniert. Wenn ich einen bereinigter Build erhalte ich ein „gelungen Build“ Nachricht in der Statusleiste VS 2008, aber ich habe auch einen Fehler in der XAML gemeldet

Type 'Test+TestEnum' was not found. 

Aber der Code ausgeführt wird, wie erwartet!

Dies bedeutet jedoch, dass der XAML-Designer nicht geladen wird. Also bin ich irgendwie damit beschäftigt, noch mehr WPF-Arbeit zu machen, bis ich den XAML-Fehler löschen kann.

Ich frage mich jetzt, ob dies ein VS 2008 SP1 Problem ist, und kein Problem meinerseits.

bearbeiten

  1. Hergestellt mein Problem Aussage deutlicher.
  2. Versuchte erste Lösung Joel, aber ich endete mit dem Code oben läuft und 2 XAML-Fehler
  3. Versuchte zweite Lösung Joel und arbeitete gerade aus der Box - so mit, dass man ich werde!

Hinweise Die SO Frage, die ich von Anwendungen dieser Art der Syntax für den XAML die Markupextension Code bekam:

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

Wenn ich, dass ich einen Kompilierungsfehler erhalten, dass Kein EnumValues-Konstruktor benötigt 1 Parameter. Ich habe etwas gegoogelt und dies scheint ein Fehler in VS zu sein. Ich verwende VS 2008 SP1. Ich habe einige Kommentare gesehen, die darauf hinwiesen, dass es in der VS 2010 Beta ist. Wie auch immer, das ist, warum ich die XAML-Syntax von

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

Da diese Syntax Werke verwenden!

+0

In Bezug auf den Fehler über den Konstruktor tritt es nur im Designer auf.Es sollte ansonsten gut funktionieren. Um diesen Fehler zu vermeiden, definieren Sie die Markup-Erweiterung in einer separaten Assembly. –

+0

@Thomas: Ich hatte vergessen, wie der Designer streitsüchtig sein kann, welche Typen wann und wo erstellt werden und wie sie instanziiert werden. –

+0

@Joel - Und Anfänger wpf Programmierer wissen diese Art von wie? Zu wissen, wie man eine Klasse in eine separate Assembly stellt, um einen Teil des Build-Tools zu erfüllen, ist IMHO eher unklar. Aber ich werde weiter damit herumalbern, bis ich ein vernünftiges Verständnis habe. Danke noch einmal. –

Antwort

3

Ein anderer Weg, um die ENUM-Werte für die Verwendung als Datenquelle zu bekommen:

<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}}" 

Beachten Sie, dass Sie immer noch die Type2Extension wegen Seltsamkeit mit TypeExtension und verschachtelten Typen benötigen. Sie benötigen jedoch nicht die zusätzliche benutzerdefinierte Markuperweiterung. Dies ist besser, wenn Sie die Liste an mehreren Stellen verwenden möchten, wie Sie es in Ihren App.xaml Ressourcen deklarieren können.

+0

Vielen Dank dafür - es hat mich viel zu lange verrückt gemacht! –

+1

Sehr schön - mir fehlte das "+" bei der Deklaration der Enumeration in den MethodParameters, und es hat mich verrückt gemacht. –

1

Was ist mit der Verwendung von x:Type Markup-Erweiterung?

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

Außer INotifyPropertyChanged für die Implementierung, kopiert ich genau Ihren Code. Ich bekomme die Fehler, die Sie bekommen, aber es scheint gut zu laufen. Es ist sehr ärgerlich, den Designer nicht laden zu können. Nichts, was ich versucht habe, hat das Problem gelöst.

Ich habe this page auf MSDN über verschachtelte Typen gefunden, und ein Vorschlag in diesem Thread war eine benutzerdefinierte MarkupExtension für die Auflösung des verschachtelten Typnamens. Ich versuche, es zur Arbeit zu bringen, aber bis jetzt kein Glück. Ich bekomme manchmal ähnliche Fehler auf Type2Extension, und ich bekomme "Der Enum-Typ ist nicht festgelegt" mit anderen Optimierungen.

Aha! Es gab einen Fehler beim Aufruf des ursprünglichen Autors GetType()! Hier ist die korrigierte Type2Extension und wie ich war mit ihm:

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)); 
     } 
    } 
} 

Und XAML:

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

Dies scheint Lasten in Ordnung und der Designer zu arbeiten. Ich werde Type2Extension zu meinen eigenen kleinen Bibliotheken hinzufügen.

Edit: Seltsamer, wenn ich das ändern in EnumValues:

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

Um dies:

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

Da nun die Konstruktor Fehler weg. Das war die eine Sache, die ich geändert habe. Ich werde jedoch in Kürze eine alternative Möglichkeit veröffentlichen, Enum-Werte zu erhalten.

+0

Wenn Sie meinen: ItemsSource = "{Bindungsquelle = {w: EnumValues ​​EnumType = {x: Geben Sie w: Test + TestEnum}}}" Dann gab nur eine große Kompilierung fehl –

+0

Interessant. Nachdem ich geantwortet habe, habe ich angefangen, Ihren Beispielcode zusammenzusetzen, um ihn neu zu erstellen (nur um zu sehen, ob es funktioniert hat). Ich werde es bearbeiten, wenn ich etwas herausgefunden habe. –

+0

Danke dafür. Ich bin jetzt zu müde, um mich damit zu beschäftigen, aber ich werde es gleich am Morgen sehen. Ich bin neu in WPF und muss mich durch diese Art von Reifen springen lassen, um das zu tun, was eigentlich Grundsätzliches sein sollte. –