2016-10-03 4 views
1

У меня есть объект, основанный на байтовых данных с более чем 200 свойствами, которые меня волнуют, в том смысле, что я хочу (1) знать значение и (2) знать, когда значение изменилось от одного сообщения к другому.WPF UserControl на основе свойств общих объектов

Отрывок из XAML, я использую:

<Label Content="Prop Name" /> 
<TextBlock Text="{Binding PropName}" 
    Background="{Binding PropName, 
     Converter={StaticResource CompareToLastValueConverter}}" /> 

В настоящее время у меня есть эти строки, вставленные для каждого свойства, с соответствующими параметрами расположения сетки.

Мой вопрос заключается в следующем: есть хороший способ, чтобы создать вложенной WPF UserControl, который принимает общее свойство объекта от модели и обрабатывает присвоение имени (с пробелами) в Label, то присвоение значения свойства TextBlock, как пример выше?

Кроме того, это лучший способ подумать об этой проблеме, или мне не хватает ссылки в «WPF-способе» делать что-то?

ответ

1

Я часто хотел попробовать это. Я бы создал шаблон ItemsControl для PropertyInfo.

Я создал тестовый класс:

public class MyClass 
    { 
     public string PropertyTest1 {get;set;} 
     public string PropertyTest2 { get; set; } 
     public string PropertyTest3 { get; set; } 
     public string PropertyTest4 { get; set; } 
    } 

Чтобы отобразить свойства. В моем контексте данных для отображения у меня есть две вещи, к которым нужно привязать. Список PropertyInfos и объект, о котором идет речь. Поскольку PropertyInfo является статическим, вы могли бы быть в состоянии сделать это лучший способ, используя конвертер или что-то, и не нужно привязать его к свойству:

public PropertyInfo[] Properties 
    { 
     get { return typeof(MyClass).GetProperties(); } 
    } 

    public MyClass MyObject 
    { 
     get { return new MyClass { PropertyTest1 = "test", PropertyTest3 = "Some string", PropertyTest4 = "Last Property" }; } 
    } 

Теперь, отображающая свойства легко:

<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}" Grid.IsSharedSizeScope="True"> 
    <ItemsControl.Resources> 
     <local:PropertyInfoValueConverter x:Key="PropertyInfoValueConverter"/> 
    </ItemsControl.Resources> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto"/> 
        <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 
       <TextBlock Text="{Binding Name}" Margin="4,2"/> 
       <TextBlock Grid.Column="1" Margin="4,2"/> 
      </Grid> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Но они являются «статическими», мы не можем привязываться к каким-либо значениям. Способ обойти это использовать свойство Tag, и мульти-связывающим преобразователь:

Так давайте добавим Tag="{Binding MyObject}" к нашему ItemsSource, и бросить, что и в PropertyInfo в преобразователе значение для нашего второго TextBlock:

   <TextBlock Grid.Column="1" Margin="4,2"> 
        <TextBlock.Text> 
         <MultiBinding Converter="{StaticResource PropertyInfoValueConverter}"> 
          <Binding Path=""/> 
          <Binding ElementName="PropertyDisplay" Path="Tag"/> 
         </MultiBinding> 
        </TextBlock.Text> 
       </TextBlock> 

преобразователь на самом деле довольно просто, тем более, что вы не используете текстовые окна (так будет только для чтения только направление):

public class PropertyInfoValueConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     PropertyInfo propertyInfo = values[0] as PropertyInfo; 
     return propertyInfo.GetValue(values[1]); 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Это результат:

enter image description here

Вы говорите, что вы хотите пространства для имен, которые можно было бы сделать с помощью преобразователя с некоторыми логики ищет любые правила именования у вас есть (пробелы перед заглавными буквами?).

Было бы здорово играть с помощью селекторов шаблонов, чтобы выбрать логические, строковые, плавающие шаблоны и относиться к ним по-разному. (Флажки, текст, 00.00 форматированный текст и т.д.)

Edit: Изучение шаблонов Selector

Вот Селектор пример шаблона:

public class PropertyInfoTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate StringTemplate { get; set; } 
    public DataTemplate IntegerTemplate { get; set; } 
    public DataTemplate DecimalTemplate { get; set; } 
    public DataTemplate BooleanTemplate { get; set; } 
    public DataTemplate DefaultTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     PropertyInfo propertyInfo = item as PropertyInfo; 
     if (propertyInfo.PropertyType == typeof(string)) 
     { 
      return StringTemplate; 
     } 
     else if (propertyInfo.PropertyType == typeof(int)) 
     { 
      return IntegerTemplate; 
     } 
     else if (propertyInfo.PropertyType == typeof(float) || propertyInfo.PropertyType == typeof(double)) 
     { 
      return DecimalTemplate; 
     } 
     else if (propertyInfo.PropertyType == typeof(bool)) 
     { 
      return BooleanTemplate; 
     } 
     return DefaultTemplate; 
    } 
} 

Наша ItemsControl теперь просто:

<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}" 
       Grid.IsSharedSizeScope="True" 
       Tag="{Binding MyObject}" 
       ItemTemplateSelector="{StaticResource PropertyInfoTemplateSelector}" 
       Margin="20"/> 

Я также добавил пространства в названиях, использующих этот преобразователь:

public class PropertyInfoNameConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     string text = value as string; 
     if (string.IsNullOrWhiteSpace(text)) 
      return string.Empty; 
     StringBuilder newText = new StringBuilder(text.Length * 2); 
     newText.Append(text[0]); 
     for (int i = 1; i < text.Length; i++) 
     { 
      if (char.IsUpper(text[i])) 
       if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) || 
        (char.IsUpper(text[i - 1]) && 
        i < text.Length - 1 && !char.IsUpper(text[i + 1]))) 
        newText.Append(' '); 
      newText.Append(text[i]); 
     } 
     return newText.ToString(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

(Задолженность: https://stackoverflow.com/a/272929/1305699).

Обновление нашего класса содержит некоторые логические и fload поля:

enter image description here

+0

очень хороший! Благодарю. – tjcertified

Смежные вопросы