2009-09-23 17 views
6

यह शायद अन्य स्थानों पर लागू होता है, लेकिन WinForms में, जब मैं बाध्यकारी का उपयोग करता हूं तो मुझे लगता है कि कई विधियां संपत्ति के नाम को बांधना चाहते हैं। की तरह कुछ:क्या सी # बाध्यकारी कार्य स्थिर रूप से बनाने का कोई तरीका है?

class Person 
{ 
    public String Name { get { ... } set { ... } } 
    public int Age { get { ... } set { ... } } 
} 

class PersonView 
{ 
    void Bind(Person p) 
    { 
     nameControl.Bind(p,"Name"); 
     ageControl.Bind(p,"Age"); 
    } 
} 

बड़ी समस्या मैं इस के साथ कर रखना है कि "नाम" और "आयु" तार के रूप में निर्दिष्ट कर रहे हैं। इसका मतलब यह है कि अगर किसी व्यक्ति की संपत्ति का नाम बदलता है तो संकलक कोई मदद नहीं करता है। कोड ठीक संकलित करेगा, लेकिन बाइंडिंग टूटा जाएगा।

क्या यह याद करने का एक मानक तरीका है जिसे मैंने याद किया है? ऐसा लगता है कि मुझे कुछ खोजशब्द की आवश्यकता है, शायद मौजूदा प्रकार से मेल खाने के लिए स्ट्रिंग को बुलाया जा सकता है। आप इसे की तरह कुछ इस्तेमाल कर सकते हैं:

ageControl.Bind(p,stringof(p.Age).Name); 

stringof कुछ वर्ग पथ, या स्ट्रिंग का पूरा पथ, भाग प्राप्त करने के लिए गुण है कि वापसी कर सकता है, तो आप इसे अपने आप को पार्स कर सकते हैं।

क्या ऐसा कुछ ऐसा पहले से ही सक्षम है?

+1

यह, यह नहीं है सी # गतिशील रूप से बांधता है कि ज्यादा उदाहरण के लिए, मौजूदा परियोजनाओं में से एक में हम इस तरह बाइंडिंग सेट WinForms हैं। –

+0

सच है। इस तरह की भाषा सुविधा काम में आ सकती है भले ही आप WinForms का उपयोग नहीं कर रहे हों। –

उत्तर

2

आप भाव का उपयोग कर सकते प्राप्त करने के लिए क्या कर सकते हैं कंपाइलर-चेक बाइंडिंग्स।

DataBinder 
    .BindToObject(this) 
    .ObjectProperty(c => c.IsReadOnly) 
     .Control(nameTextBox, n => n.ReadOnly) 
     .Control(addressControl, n => n.ReadOnly) 

कोड इस शैली का समर्थन कई वर्गों में विभाजित किया गया है:

public static class DataBinder 
{ 
    public static DataBinderBindingSourceContext<TDataSource> BindToObject<TDataSource>(TDataSource dataSource) 
    { 
     return new DataBinderBindingSourceContext<TDataSource>(dataSource); 
    } 
} 

public class DataBinderBindingSourceContext<TDataSource> 
{ 
    public readonly object DataSource; 

    public DataBinderBindingSourceContext(object dataSource) 
    { 
     DataSource = dataSource; 
    } 

    public DataBinderControlContext<TDataSource, TProperty> ObjectProperty<TProperty>(Expression<Func<TDataSource, TProperty>> property) 
    { 
     return new DataBinderControlContext<TDataSource, TProperty>(this, property); 
    } 
} 

public class DataBinderControlContext<TDataSource, TProperty> 
{ 
    readonly DataBinderBindingSourceContext<TDataSource> BindingSourceContext; 
    readonly string ObjectProperty; 

    public DataBinderControlContext 
     (
      DataBinderBindingSourceContext<TDataSource> bindingSourceContext, 
      Expression<Func<TDataSource, TProperty>> objectProperty 
     ) 
    { 
     BindingSourceContext = RequireArg.NotNull(bindingSourceContext); 
     ObjectProperty = ExpressionHelper.GetPropertyName(objectProperty); 
    } 

    public DataBinderControlContext<TDataSource, TProperty> Control<TControl>(TControl control, Expression<Func<TControl, TProperty>> property) 
     where TControl : Control 
    { 
     var controlPropertyName = ExpressionHelper.GetPropertyName(property); 
     control.DataBindings.Add(controlPropertyName, BindingSourceContext.DataSource, ObjectProperty, true); 

     return this; 
    } 
} 

public static class ExpressionHelper 
{ 
    public static string GetPropertyName<TResult>(Expression<Func<TResult>> property) 
    { 
     return GetMemberNames(((LambdaExpression)property).Body).Skip(1).Join("."); 
    } 

    public static string GetPropertyName<T, TResult>(Expression<Func<T, TResult>> property) 
    { 
     return GetMemberNames(((LambdaExpression)property).Body).Join("."); 
    } 

    static IEnumerable<string> GetMemberNames(Expression expression) 
    { 
     if (expression is ConstantExpression || expression is ParameterExpression) 
      yield break; 

     var memberExpression = (MemberExpression)expression; 

     foreach (var memberName in GetMemberNames(memberExpression.Expression)) 
      yield return memberName; 

     yield return memberExpression.Member.Name; 
    } 
} 

public static class StringExtentions 
{ 
    public static string Join(this IEnumerable<string> values, string separator) 
    { 
     if (values == null) 
      return null; 

     return string.Join(separator, values.ToArray()); 
    } 
} 
0

आप प्रतिबिंब का उपयोग नाम ;-)

निश्चित रूप से यह पता लगाने के लिए कर सकता है एक परिपत्र संदर्भ हो सकता है, आप नाम का उपयोग करेंगे आपको लगता है कि (या कुछ भी नहीं मिल करने के लिए यह एक ही नाम को मिल रहा है , जिसका अर्थ है कि संपत्ति का नाम बदल दिया गया था ... लेकिन एक विचार है (या बल्कि, एक चाल): उस संपत्ति के लिए कुछ भी नहीं करने के संदर्भ में, जिसे आप उपयोग करना चाहते हैं, आपको संकलन समय की पुष्टि मिल जाएगी कि यह अभी भी है। केवल समस्या यह है कि अगर कोई व्यक्ति केवल विभिन्न संपत्ति नामों को स्वैप करता है; उस स्थिति में, नाम अभी भी मौजूद हैं (कोई संकलन-समय त्रुटि नहीं है), लेकिन अलग-अलग एप्लिकेशन-स्तरीय अर्थशास्त्र (एप्लिकेशन के आउटपुट में संभावित आश्चर्य)

4

पर एक नज़र डालें यह code snippet मैंने एक और प्रश्न में पोस्ट किया है, यह आपकी मदद कर सकता है! (लेकिन केवल, आप .NET 3.5 उपयोग कर रहे हैं)

बेस्ट सादर
ओलिवर Hanappi

4

आपको लगता है कि अभिव्यक्ति के पेड़ के साथ, के रूप में समझाया in this question

protected static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression) 
{ 
    if (expression.NodeType == ExpressionType.Lambda && expression.Body.NodeType == ExpressionType.MemberAccess) 
    { 
     PropertyInfo prop = (expression.Body as MemberExpression).Member as PropertyInfo; 
     if (prop != null) 
     { 
      return prop.Name; 
     } 
    } 
    throw new ArgumentException("expression", "Not a property expression"); 
} 

... 

ageControl.Bind(p, GetPropertyName((Person p) => p.Age)); 
संबंधित मुद्दे