2012-11-12 39 views
6

कैलिबर्न। माइक्रो का Catel's[ExposeAttribute] पर समान कार्य है?कैलिबर्न में आसान पास-थ्रू-प्रॉपर्टीज। मैट्रो कैटेल के [एक्सपोज़ एट्रिब्यूट]

कैलिबर में पास-थ्रू-प्रॉपर्टी के काम को कम करने का कोई और तरीका है। माइक्रो? (Ie गुण है कि मॉडल में बल्कि ViewModel में हैं दृश्य गुण का उपयोग करने की अनुमति देने के लिए।)

उत्तर

7

परिभाषित ExposeAttribute:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 
public class ExposeAttribute : Attribute 
{ 
    public ExposeAttribute(string propertyName) 
    { 
     PropertyName = propertyName; 
    } 

    public ExposeAttribute(string propertyName, string modelPropertyName) 
    { 
     PropertyName = propertyName; 
     ModelPropertyName = modelPropertyName; 
    } 

    public string PropertyName { get; set; } 

    public string ModelPropertyName { get; set; } 
} 

और का उपयोग इस ExposedPropertyBinder मैं सिर्फ तुम्हारे लिए :)

लिखा था
public static class ExposedPropertyBinder 
{ 
    private static readonly ILog Log = LogManager.GetLog(typeof(ExposedPropertyBinder)); 

    public static void BindElements(IEnumerable<FrameworkElement> elements, Type viewModelType) 
    { 
     foreach (var element in elements) 
     { 
      var parts = element.Name.Trim('_') 
       .Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries); 

      // Get first exposed property 
      var exposedPropertyInfo = GetExposedPropertyInfo(viewModelType, parts[0]); 
      if (exposedPropertyInfo == null) 
      { 
       Log.Info("Binding Convention Not Applied: Element {0} did not match a property.", element.Name); 
       continue; 
      } 

      var breadCrumb = new List<string> { exposedPropertyInfo.Path }; 

      // Loop over all parts and get exposed properties 
      for (var i = 1; i < parts.Length; i++) 
      { 
       var exposedViewModelType = exposedPropertyInfo.ViewModelType; 

       exposedPropertyInfo = GetExposedPropertyInfo(exposedViewModelType, parts[i]); 
       if (exposedPropertyInfo == null) break; 

       breadCrumb.Add(exposedPropertyInfo.Path); 
      } 

      if (exposedPropertyInfo == null) 
      { 
       Log.Info("Binding Convention Not Applied: Element {0} did not match a property.", element.Name); 
       continue; 
      } 

      var convention = ConventionManager.GetElementConvention(element.GetType()); 
      if (convention == null) 
      { 
       Log.Warn("Binding Convention Not Applied: No conventions configured for {0}.", element.GetType()); 
       continue; 
      } 

      var applied = convention.ApplyBinding(exposedPropertyInfo.ViewModelType, 
       string.Join(".", breadCrumb), exposedPropertyInfo.Property, element, convention); 

      var appliedMessage = string.Format(applied 
       ? "Binding Convention Applied: Element {0}." 
       : "Binding Convention Not Applied: Element {0} has existing binding.", element.Name); 

      Log.Info(appliedMessage); 
     } 
    } 

    private static ExposedPropertyInfo GetExposedPropertyInfo(Type type, string propertyName) 
    { 
     foreach (var property in type.GetProperties()) 
     { 
      if (property.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase)) 
       return new ExposedPropertyInfo(property.PropertyType, property.Name, property); 

      // Get first ExposeAttribute which matches property name 
      var exposeAttribute = GetExposeAttribute(property, propertyName); 
      if (exposeAttribute == null) continue; 

      // Get the name of the exposed property 
      var exposedPropertyName = exposeAttribute.ModelPropertyName ?? exposeAttribute.PropertyName; 

      var path = string.Join(".", property.Name, exposedPropertyName); 
      var viewModelType = property.PropertyType; 
      var propertyInfo = property; 

      // Check if property exists 
      var exposedProperty = viewModelType.GetPropertyCaseInsensitive(exposedPropertyName); 
      if (exposedProperty == null) 
      { 
       // Do recursive check for exposed properties 
       var child = GetExposedPropertyInfo(viewModelType, exposedPropertyName); 
       if (child == null) continue; 

       path = string.Join(".", property.Name, child.Path); 
       viewModelType = child.ViewModelType; 
       propertyInfo = child.Property; 
      } 

      return new ExposedPropertyInfo(viewModelType, path, propertyInfo); 
     } 

     return null; 
    } 

    private static ExposeAttribute GetExposeAttribute(PropertyInfo property, string propertyName) 
    { 
     return property 
      .GetCustomAttributes(typeof(ExposeAttribute), true) 
      .Cast<ExposeAttribute>() 
      .FirstOrDefault(a => a.PropertyName.Equals(propertyName, StringComparison.OrdinalIgnoreCase)); 
    } 

    private class ExposedPropertyInfo 
    { 
     public ExposedPropertyInfo(Type viewModelType, string path, PropertyInfo property) 
     { 
      ViewModelType = viewModelType; 
      Path = path; 
      Property = property; 
     } 

     public Type ViewModelType { get; private set; } 

     public string Path { get; private set; } 

     public PropertyInfo Property { get; private set; } 
    } 
} 

यह तार ऊपर Caliburn.Micro के ViewModelBinder इस तरह करने के लिए:

ViewModelBinder.HandleUnmatchedElements = ExposedPropertyBinder.BindElements; 

और वॉयला!

ExposeAttribute के साथ अपने ViewModel गुण डेकोरेट:

public class MainViewModel : PropertyChangedBase 
{ 
    private Person _person; 

    [Expose("FirstName")] 
    [Expose("LastName")] 
    [Expose("ZipCode")] 
    public Person Person 
    { 
     get { return _person; } 
     set 
     { 
      _person = value; 
      NotifyOfPropertyChange(() => Person); 
     } 
    } 
} 

public class Person 
{ 
    public string FirstName { get; set; } 

    public string LastName { get; set; } 

    [Expose("ZipCode", "zip_code")] 
    public Address Address { get; set; } 

    public string FullName 
    { 
     get { return string.Join(" ", FirstName, LastName); } 
    } 

    public override string ToString() 
    { 
     return FullName; 
    } 
} 

public class Address 
{ 
    public string zip_code { get; set; } 
} 

और बाँध अपने गुण के लिए:

<TextBlock x:Name="Person_FullName" /> 
    <TextBlock x:Name="FirstName" /> 
    <TextBlock x:Name="LastName" /> 
    <TextBlock x:Name="ZipCode" />     // 
    <TextBlock x:Name="Person_ZipCode" />   // THESE ARE THE SAME ;) 

REMARK: यह मेरा सरल उदाहरण के लिए काम किया है, लेकिन इस बड़े पैमाने पर परीक्षण नहीं किया गया तो देखभाल के साथ इसका इस्तेमाल करें।

आशा है कि यह आपके लिए काम करता है! :)

संपादित: एक थोड़ा संशोधित संस्करण अब GitHub और NuGet

+0

कि बहुत अच्छा है पर पाया जा सकता। धन्यवाद! हालांकि यह परीक्षण करने का एक अच्छा मौका मिलने से पहले कुछ समय होगा। – kasperhj