2012-03-27 9 views
1

Ich versuche, ein benutzerdefiniertes Attribut in C# einzurichten, um festzulegen, ob eine Geschäftsobjekteigenschaft editierbar ist, wodurch ReadOnly ein Textfeld in XAML aktiviert oder deaktiviert wird. Da (dachte ich) IsEditable bereits in System.Windows.Controls umgesetzt wurde, dachte ich, das funktionieren würde:Ein benutzerdefiniertes Attribut zum Festlegen, ob ein Textfeld editierbar ist

[AttributeUsage(AttributeTargets.Property)] 
public class EditableAttribute : Attribute 
{ 
    public EditableAttribute(bool isEditable) 
    { 
     this.ReadOnly = !isEditable; 

    } 
    public virtual bool ReadOnly { get; set; } 
} 

Nun, gehen Figur, es funktioniert nicht. Ich setze [Editierbar (falsch)] auf eine Zeichenkette in einem Objekt und es ist noch editierbar. Ich habe das Gefühl, dass ich nicht einmal in der Nähe bin. Jede Hilfe oder Vorschläge würden sehr geschätzt werden!

Ich bin mir bewusst, dass dies als ein Stil in XAML eingerichtet werden kann, aber für diesen Fall muss es im Business-Objekt sein.

Dank

Antwort

1

Sie können BindingDecoratorBase verwenden, um benutzerdefinierte Bindung zu verwenden und ein Attribut zu verwenden.

Der folgende Code ist nur ich ändern meinen Code in meinem Projekt, das custom validation verwendet. Es sollte wahrscheinlich refraktiert werden.

public interface IEditatble 
{ 
    void SetValue(Control sender, DependencyProperty property); 
} 

[AttributeUsage(AttributeTargets.Property)] 
public class EditableAttribute : Attribute, IEditatble 
{ 
    public EditableAttribute(bool isEditable) 
    { 
     this.ReadOnly = !isEditable; 

    } 
    public virtual bool ReadOnly { get; set; } 

    public void SetValue(System.Windows.Controls.Control sender, System.Windows.DependencyProperty property) 
    { 
     sender.SetValue(property, this.ReadOnly); 
    } 
} 

Sie können eine benutzerdefinierte erstellen Bindung:

public class ReadonlyBinding : BindingDecoratorBase 
{ 
    private DependencyProperty _targetProperty = null; 
    public ReadonlyBinding() 
    : base() 
    { 
     Binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 
    } 

    public override object ProvideValue(IServiceProvider provider) 
    { 
     // Get the binding expression 
     object bindingExpression = base.ProvideValue(provider); 

     // Bound items 
     DependencyObject targetObject; 

     // Try to get the bound items 
     if (TryGetTargetItems(provider, out targetObject, out _targetProperty)) 
     { 
      if (targetObject is FrameworkElement) 
      { 
       // Get the element and implement datacontext changes 
       FrameworkElement element = targetObject as FrameworkElement; 
       element.DataContextChanged += new DependencyPropertyChangedEventHandler(element_DataContextChanged); 
      } 
     } 

     // Go on with the flow 
     return bindingExpression; 
    } 

    void element_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     object datacontext = e.NewValue; 
     if (datacontext != null && _targetProperty != null) 
     { 
      PropertyInfo property = datacontext.GetType().GetProperty(Binding.Path.Path); 
      if (property != null) 
      { 
       var attribute = property.GetCustomAttributes(true).Where(o => o is IEditatble).FirstOrDefault(); 
       if (attribute != null) 
       {       
        Control cntrl = sender as Control; 
        ((IEditatble)attribute).SetValue(cntrl, _targetProperty); 
       } 

      } 
     } 
    } 
} 

Und Sie können es gerne verwenden:

[Editable(true)] 
public string Name { get; set; } 

XAML:

<TextBox IsReadOnly="{local:ReadonlyBinding Path=Name}" /> 
1

Für Ihre EditableAttribute sollten arbeiten, TextBox Klassen Reflexion über Ihr Modell verwenden, um zu überprüfen, ob das Attribut gesetzt ist und die notwendigen Eigenschaften festgelegt. Ich möchte damit sagen, dass dieses Attribut nicht mehr als Metadaten ist und den Anwendungsworkflow nur dann steuert, wenn die Anwendung dies wünscht.

Sie können von Basic TextBox erben und die erforderliche Funktionalität einfügen, obwohl es ein Overkill ist. Sie sollten nur die Variable IsSomePropertyReadOnly deklarieren und an sie in TextBox binden.

Obwohl, wenn Sie wirklich Lust fühlen, könnten Sie einige Wrapper-Klasse schreiben wie

public class ReadOrWriteText<T> 
{ 
    private T _value; 
    bool IsReadOnly { get; set; } 

    public T Value 
    { 
     get { return _value; } 
     set { if (IsReadOnly) return; _value = value; } 
    } 
} 

und binden es IsReadOnly und Value-Eigenschaften. Obwohl es auch ein Overkill ist.

Verwandte Themen