2012-11-12 14 views

Trả lời

7

Xác định 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; } 
} 

Và sử dụng ExposedPropertyBinder này tôi chỉ viết cho bạn :)

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

Wire nó lên đến Caliburn.Micro của ViewModelBinder như thế này:

ViewModelBinder.HandleUnmatchedElements = ExposedPropertyBinder.BindElements; 

Và thì đấy!

Trang trí tính ViewModel của bạn với ExposeAttribute:

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

Và liên kết với tài sản của bạn:

<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: Điều này làm việc cho các ví dụ đơn giản của tôi, nhưng điều này chưa được thử nghiệm rộng rãi vì vậy hãy sử dụng nó cẩn thận.

Hy vọng nó phù hợp với bạn! :)

EDIT: Một phiên bản sửa đổi một chút bây giờ có thể được tìm thấy trên GitHubNuGet

+0

Đó là khá mát mẻ. Cảm ơn! Nó sẽ được một thời gian trước khi tôi nhận được một cơ hội tốt để thử nghiệm này mặc dù. – kasperhj

Các vấn đề liên quan