powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Атрибуты свойств модели - через модель представления - привязать к представлению - как?
23 сообщений из 23, страница 1 из 1
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125840
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WPF, MVVM.

В модели есть, например, класс:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
class MyModel
{
	[Display(
		ResourceType = typeof(Resources.Strings),
		Name = "MyName",
		Description = "MyDescription")]
	public double MyProperty { get; set; }
}




В модели представления:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public class MyVM
{
	private Models.MyModel model;

	public string MyVMProperty
	{
		get { return model.MyProperty.ToString(); }
		set
		{
			double val;
			double.TryParse(value, out val);
			if (val != model.MyProperty)
			{
				model.MyProperty = val;
			}
		}
	}
}



В представлении хочу сделать что-то типа этого:

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<TextBlock 
	Text="{Binding Path=MyVMProperty}" 
	/>

<TextBlock 
	Text="{Binding Path=MyVM.model.MyProperty.DisplayAttribute.Name}" 
	/>

<TextBlock 
	Text="{Binding Path=MyVM.model.MyProperty.DisplayAttribute.Name}" 
	/>




Т. е. хочу "протащить" значения атрибутов каждого свойства из модели в представления. Как сделать? Не создавать же в модели представления для каждого свойства модели ещё и "обвязку" в виде свойств для каждого свойства каждого атрибута?


Пробовал в гугле искать на английском примерно то же, что в названии темы - вообще ноль. Такое ощущение, что я что-то делаю не так и никто такой задачей не задавался.

Кстати, везде в примерах с атрибутами их задают сразу для модели представления и привязывают эти атрибуты как-то (через конвертеры, например) к представлению. Но чтобы как я хочу - ничего нет.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125841
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Последняя привязка не к Name, а к Description.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125863
Фотография Местный король Делфей
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я бы конвертер написал
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125886
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тут вот ещё в чём штука. Те три текстовых поля в XAML'e объединены в юзер контрол, который байндится к экземпляру MyVM. Поэтому первый текстблок (там текстбокс должен быть вообще-то, но неважно) я могу сразу привязать к MyVMProperty, что и сделано. А остальные - через конвертер, как вы и сказали. Но тут сложности у меня возникли. По идее, надо из конвертера достать свойства атрибутов свойств МОДЕЛИ (во сколько вложенностей!). Т. е. надо сделать так, как я понимаю:

1) в конвертер передать:

а) тип модели;
б) имя свойства модели;
в) тип атрибута свойства модели;
г) имя свойства атрибута указанного свойства модели (само по себе уже некисло!);

2) в конвертере:

а) из типа модели достать её свойство указанного имени;
б) узнать тип этого свойства;
в) у узнанного типа свойства модели достать атрибут указанного типа;
г) у этого утрибута достать свойство указаного имени и вернуть его.

Я правильно всё понимаю?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125890
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то много ручной писанины получится. Получается, я в представлении пишу, как устроена модель (не модель представления даже, а модель) - имена свойств, их типы, имена свойств атрибутов и прочее. Получается сильная связь.

Неужели нет простого способа, если хочешь свойства свойств модели показать в представлении?

Ну вроде бы распространённая задача: есть группа настроек, есть настройки в этой группе, у каждой настройки описание и название. Настройку помещяю в свойство объекта группы настроек, а описание и название - в метаданные этого СВОЙСТВА (т. е. в атрибуты настройки). Это всё модель. В модели представления представляю ТОЛЬКО саму настройку, без её метаданных - т. е. НЕ завожу ещё кучу полей, каждое из которых представляет КАЖДОЕ свойство КАЖДОГО атрибута КАЖДОГО свойства модели ("свойства" два раза повторяется - это не ошибка). Как достать значения свойств этих атрибутов из модели в представлении?

Если заводить свойства для свойств атрибутов модели, то получится вот что. Положим, у меня 2 свойства в модели. У каждого свойства по 2 атрибута. У каждого из этих двух атрибутов по 2 своих свойства. Тогда в модели представления мне надо завести 2 свойства, представляющих свойства модели, и 2*2*2=8 свойств, представляющих метаданные свойств модели! Это же неправильно!
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125901
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всё было бы проще, если бы модель представления унаследовала метаданные модели (все эти атрибуты и их значения). Только без собственно наследования. Можно это как-то сделать?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125905
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Т. е. я хочу, чтобы у каждого свойства модели представления появились такие же атрибуты, как у соответствующих свойств модели, но чтобы я руками их сам не вбивал, а чтобы они как-то сами там оказались. Как это сделать в коде?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38125973
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, по тому, что я написал, уже понятно, что конвертер не подходит. Мне надо передать имя свойства модели и имя своства атрибута модели - уже два параметра, в то время как у конвертера он только один. Конвертер со множеством значений (IMultiValueConverter) тоже не подходит, т. к. эти значения - это не параметры. Параметр по-прежнему один, а значения - это свойства привязываемой модели. Т. е., чтобы воспользоваться IMultiValueConverter, надо обернуть каждое свойство модели представления в некий класс со свойствами, которые и будут выступать в качетсве значений IMultiValueConverter. Т. е. целый класс-обёртку городить.

Самое разумное было бы - предоставить возможность конвертеру (даже обычному, не надо IMultiValueConverter), принимать множество параметров. Тогда бы я мог туда и имена свойств передать, и их типы. В принципе, я могу это сделать и так, затолкав все эти данные в один параметр-строку с символами-разделителями и распарсив её в конвертере. Но это уже получится, что я борюсь со фреймворком, вместо того, чтобы его использовать. Отсюда вывод, что для того, чего я хочу, создатели фреймворка ничего не предусмотрели - приходится делать свои костыли.

Это навело меня на мысль, что не является ли это неправильным подходом - предоставлять метаданные модели в представлении сразу? Может, более правильным будет, когда метаданные модели в модели представления представляются ОБЫЧНЫМИ ДАННЫМИ? Тогда и не надо будет никаких конвертеров - бери и привязывай данные напрямую. Тогда мысль с классом обёрткой была правильная. Т. е. каждое свойство модели представления - это не просто трансляция свойств модели, а объект с полями, представляющими собой собственно свойство модели, плюс метаданные свойства моделит, но уже в виде обычных данных.

Как вы считаете?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126095
SeVa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Правильно будет не устраивать подобные мультики из-за трех textbox. Если уж так хочется, то создавай свой контрол, который будет использовать атрибуты свойства. По такому принципу построена dataform
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126111
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Мне надо передать имя свойства модели и имя своства атрибута модели - уже два параметра, в то время как у конвертера он только один.
Во-первых, можно не страдать излишним перфекционизмом, и сделать несколько конвертеров под определенный тип модели и атрибута - тогда параметром будет достаточно передать имя поля атрибута.
Во-вторых, в данном случае постановка задачи содержит ошибку - никак не задана связь MyVM.MyVMProperty и MyModel.MyProperty - её не вытащить и с помощью reflection.
Если перенести атрибут на MyVM.MyVMProperty, то без конвертеров с вхардкоденными моделью/атрибутом задачу можно решить через собственную реализацию MarkupExtension. Примерный вариант можно посмотреть здесь , но у этого примера есть один недастаток: он не позволяет именно в разметке забиндиться на значение поля атрибута. Это решается примерно так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
[MarkupExtensionReturnType(typeof(BindingExpression))]
public class MetaDataBindingExtension : MarkupExtension
{
  private readonly string _path;
  public MetaDataBindingExtension(string path)
  {
    _path = path;
  }
  public IValueConverter Converter { get; set; }
  public object ConverterParameter { get; set; }
  public Type AttributeType { get; set; }

  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    var valueTarget = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
    var element = valueTarget.TargetObject as FrameworkElement;
    if (element==null) return null;
    var propertyBinding = new Binding
    {
      Path = new PropertyPath("MetaData"),
      Source = new MetaDataExtractor(element, _path),
      Mode = BindingMode.OneWay
    };
    return propertyBinding.ProvideValue(serviceProvider);
  }
}

class MetaDataExtractor: INotifyPropertyChanged
{
  private readonly FrameworkElement _source;
  private readonly string _path;
  public MetaDataExtractor(FrameworkElement source, string path)
  {
    _source = source;
    _path = path;
    _source.DataContextChanged += (s, e) =>
    {
      if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs("MetaData"));
    };
  }

  public string MetaData
  {
    get
    {
      return ExtractMEtaData();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  private string ExtractMEtaData()
  {
    if (_source.DataContext == null) return null;
    var parts = _path.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
    if (parts.Length!=3)
      throw new ApplicationException("Malformed metadata path");
    var property = TypeDescriptor.GetProperties(_source.DataContext)
      .Find(parts[0], false);
    if (property == null) return null;
    var attribute = property.Attributes.Cast<Attribute>()
      .FirstOrDefault(attr => attr.GetType().Name == parts[1]);
    if (attribute == null) return null;
    var attrProperty = attribute.GetType().GetProperty(parts[2]);
    return attrProperty != null ? (string)attrProperty.GetValue(attribute, new object[] { }) : null;
  }
}


Тогда в разметке действительно можно будет написать так:
Код: xml
1.
2.
<TextBlock Text="{l:MetaDataBinding MyVMProperty.DisplayAttribute.Name}"/>
<TextBox Text="{Binding MyVMProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>


Преимущество такого решения перед конвертером в том, что в свойствах MetaDataBindingExtension можно задать всё, что потребуется далее - например, тип атрибута, который далее можно будет контролировать при извлечении атрибутов.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126145
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Самое разумное было бы - предоставить возможность конвертеру (даже обычному, не надо IMultiValueConverter), принимать множество параметров. Тогда бы я мог туда и имена свойств передать, и их типы.
Это, кстати, вполне возможно:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
public class MetadataParameters
{
  public Type AttributeType { get; set; }
  public string ModelProperty { get; set; }
  public string MetadataProperty { get; set; }
}

public class MetadataConverter: IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    if (value == null) return null;
    var mp = parameter as MetadataParameters;
    if (mp == null) return null;
    var property = TypeDescriptor.GetProperties(value)
      .Find(mp.ModelProperty, false);
    if (property == null) return null;
    var attribute = property.Attributes.Cast<Attribute>()
      .FirstOrDefault(attr => attr.GetType()==mp.AttributeType);
    if (attribute == null) return null;
    var attrProperty = attribute.GetType().GetProperty(mp.MetadataProperty);
    return attrProperty != null ? attrProperty.GetValue(attribute, new object[] { }) : null;
  }

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


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<TextBlock>
  <TextBlock.Text>
    <Binding
      Mode="OneWay"
      Converter="{StaticResource MetadataConverter}">
      <Binding.ConverterParameter>
        <l:MetadataParameters
          AttributeType="{x:Type DataAnnotations:DisplayAttribute}"
          ModelProperty="MyVMProperty"
          MetadataProperty="Name"/>
      </Binding.ConverterParameter>
    </Binding>
  </TextBlock.Text>
</TextBlock>
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126254
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторВо-первых, можно не страдать излишним перфекционизмом, и сделать несколько конвертеров под определенный тип модели и атрибута - тогда параметром будет достаточно передать имя поля атрибута.
У меня до десяти типов модели, которые надо показывать в интерфейсе (и ещё больше может быть в будущем), плюс атрибуты тоже разные могут использоваться - минимум уже Display и Range. 10х2=20 конвертеров писать, у которых шаблонный код. Нет уж.

Мне маленькая простыня во втором вашем посте нравится больше, чем большая в первом. Но всё это меня тревожит вот в чём. Всё, для чего требуются такие простыни кода - это борьба со фреймворком. Разве то, что я хочу - показать в представлении метаданные модели - это так много? Нет удобного средства во фреймворке сделать это? Вроде, это распространённая задача. Получается, что каждый первый, кто сталкивается с этим (а с этим сталкивается, похоже, каждый первый) пишет свою простыню кода на такую распространённую задачу, а создатели фреймворка вот уже десять лет не могут её отшаблонить, хотя всяких ТоСтрингов делают по шестнадцать перегрузов зачем-то?


Ладно. У меня относительно второго поста Сон Веры Павловны вопрос - этот класс MetadataParameters надо куда заводить? Получается, что для каждого свойства модели представления надо заводить по одному свойству MetadataParameters? Или придумывать класс, в который помещать одно свойство типа MetadataParameters, а второе - собственно свойство модели?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126256
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ой, последний вопрос отменяется. Я не разглядел, что в байндинге можно для кастомного типа параметра в разметке свойства этого параметра задавать. Тогда вроде должно получиться. Спасибо.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126480
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так, я немножко изменил код и довёл его до ума. Надо было в конвертере не из value тип брать, т. к. понятно, что тип там будет - один из моделей представления, а завести четвёртое свойство класса MetadataParameters, которое будет содержать тип модели (не модели представления). Дальше всё то же самое по сути.

Только вопрос, почему вы написали

Код: c#
1.
2.
var property = TypeDescriptor.GetProperties(value)
      .Find(mp.ModelProperty, false);



хотя в другом месте писали уже

Код: c#
1.
var attrProperty = attribute.GetType().GetProperty(mp.MetadataProperty);



Я сделал и там и там одинаковым образом. Вот что у меня получилось:

Это в модели представления конвертер и вспомогательный класс к нему:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
namespace MyProject.Converters
{
	public class MetadataParameters
	{
		public Type ModelType { get; set; }
		public string ModelProperty { get; set; }
		public Type AttributeType { get; set; }
		public string AttributeProperty { get; set; }
	}

	public class MetadataConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			var mp = parameter as MetadataParameters;
			if (parameter == null)
				return null;

                        if (mp.ModelType == null
                            || string.IsNullOrEmpty(mp.ModelProperty)
                            || mp.AttributeType == null
                            || string.IsNullOrEmpty(mp.AttributeProperty))
                            throw new Exception(
                                new StringBuilder()
                                .Append("Not complete MetadataParameters object is provided.\n\n")
                                .Append("Specify all the properties of MetadataParameters object.")
                                .ToString());

			var modelPropertyInfo = mp.ModelType.GetProperty(mp.ModelProperty);
			if (modelPropertyInfo == null)
				return null;

			var attribute = modelPropertyInfo
				.GetCustomAttributes(true)
				.Cast<Attribute>()
				.FirstOrDefault(memberInfo => memberInfo.GetType() == mp.AttributeType);
			if (attribute == null)
				return null;

			var attributeProperty = attribute.GetType().GetProperty(mp.AttributeProperty);
			if (attributeProperty == null)
				return null;

			return attributeProperty.GetValue(attribute, null);
		}

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




Это разметка:

В файле ресурсов (XAML):

Код: xml
1.
2.
3.
xmlns:converters="clr-namespace:DMT.Converters"
...
<converters:MetadataConverter x:Key="metadataConverter" />




В файле представления (XAML):

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
xmlns:converters="clr-namespace:MyProject.Converters"
xmlns:DataAnnotations="clr-namespace:System.ComponentModel.DataAnnotations;assembly=System.ComponentModel.DataAnnotations"
xmlns:Models="clr-namespace:MyProject.Models"
...
<TextBlock 
	<TextBlock.Text>
		<Binding
			Mode="OneWay"
			Converter="{StaticResource metadataConverter}">
			<Binding.ConverterParameter>
				<converters:MetadataParameters
					ModelType="{x:Type Models:Model}"
					ModelProperty="ModelProperty"
					AttributeType="{x:Type DataAnnotations:DisplayAttribute}"
					AttributeProperty="Name" />                            
			</Binding.ConverterParameter>
		</Binding>
	</TextBlock.Text>
</TextBlock>
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126485
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ещё я не понял, зачем в строчке

Код: c#
1.
return attrProperty != null ? attrProperty.GetValue(attribute, new object[] { }) : null;



вы написали new object[] { }. Я передал null и всё работало.




Но теперь у меня другая проблема. Я, конечно, получаю то, что в модели в атрибуты завёл. Но в свойства этих атрибутов всё подставляется из ресрусрыных локализованных строк. Я догадываюсь, что можно как-то использовать параметр CultureInfo culture конвертера, но как?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126489
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что интересно, мне вообще не понадобился параметр value конвертера. И вся привязка к подели представления оказалась нужна только для того, чтобы передать конвертеру параметр, т. к. конвертеры без привязки не работают.

Получается, что должно быть какое-то другое решение, без привязок, так как привязка по сути здесь выступает в роли костыля, который я использую только для вызова функции конвертера?
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126659
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320,

Если нужно отобразить данные в ContentControl (например, в Label), то можно напрямую использовать этот самый MetadataParameters с переопределенным ToString:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class MetadataParameters
{
  public Type ModelType { get; set; }
  public Type AttributeType { get; set; }
  public string ModelProperty { get; set; }
  public string MetadataProperty { get; set; }

  public override string ToString()
  {
    var property = TypeDescriptor.GetProperties(ModelType)
      .Find(ModelProperty, false);
    if (property == null) return string.Empty;
    var attribute = property.Attributes.Cast<Attribute>()
      .FirstOrDefault(attr => attr.GetType() == AttributeType);
    if (attribute == null) return string.Empty;
    var attrProperty = attribute.GetType().GetProperty(MetadataProperty);
    return attrProperty != null ? (string)attrProperty.GetValue(attribute, new object[] { }) : string.Empty;
  }
}


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<Label>
  <Label.Content>
    <l:MetadataParameters
      AttributeType="{x:Type DataAnnotations:DisplayAttribute}"
      ModelType="{x:Type l:MyVM}"
      ModelProperty="MyVMProperty"
      MetadataProperty="Name"/>
  </Label.Content>
</Label>


В случае с TextBlock такое не пройдет - содержимое свойства Text обязательно должно быть либо string, либо MarkupExtension - т.е. у нас только последний вариант. И в этом custom MarkupExtension вовсе не нужен binding - из ProvideValue можно сразу возвращать требуемое:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
[MarkupExtensionReturnType(typeof(string))]
public class MetaDataBindingExtension : MarkupExtension
{
  public Type ModelType { get; set; }
  public string ModelProperty { get; set; }
  public Type AttributeType { get; set; }
  public string MetadataProperty { get; set; }

  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    var property = TypeDescriptor.GetProperties(ModelType)
      .Find(ModelProperty, false);
    if (property == null) return null;
    var attribute = property.Attributes.Cast<Attribute>()
      .FirstOrDefault(attr => attr.GetType() == AttributeType);
    if (attribute == null) return null;
    var attrProperty = attribute.GetType().GetProperty(MetadataProperty);
    return attrProperty != null ? attrProperty.GetValue(attribute, new object[] { }) : null;
  }
}


Использование:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<TextBlock>
  <TextBlock.Text>
    <l:MetaDataBinding
      AttributeType="{x:Type DataAnnotations:DisplayAttribute}"
      ModelType="{x:Type l:MyVM}"
      ModelProperty="MyVMProperty"
      MetadataProperty="Name"/>
  </TextBlock.Text>
</TextBlock>


Нюанс: из-за одного достаточно старого бага при попытке использовать этот MarkupExtension в атрибутной нотации - вида
Код: xml
1.
2.
3.
<TextBlock
  Text="{l:MetaDataBinding AttributeType={x:Type DataAnnotations:DisplayAttribute}, ...}"
  ...


компилятор будет ругаться примерно так:

Код: plaintext
1.
Unknown property ‘AttributeType’ for type ‘MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension’
encountered while parsing a Markup Extension.

Причина - в наличии nested extensions (TypeExtension в данном случае). Если использовать property element syntax (как указано в первом примере разметки для TextBlock), то всё скомпилируется нормально.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126680
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо.

А не могли бы вы подсказать ещё, как вытащить нужной культуры текст из свойств метаданных модели? Я делаю так и у меня не выходит:

В модели

Код: c#
1.
2.
3.
4.
5.
[Display(
	ResourceType = typeof(Locals.Models.Settings.Common.Strings),
	Name = "ExceedThresholdName",
	Description = "ExceedThresholdDescription")]
public double ExceedThreshold { get; set; }



При этом в сборке модели файл с нужными строками есть - Strings.ru-RU.resx. Также есть дефолтный файл - Strings.resx, который повторяет содержимое ru-RU.

В приложении, представляющем модель представления и представление:

Код: c#
1.
2.
3.
4.
5.
6.
7.
public partial class App : Application
{
	public App()
	{
		Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ru-RU");
	}
}



В конвертере (я пока его использую):

Код: c#
1.
2.
3.
4.
5.
6.
return attributeProperty.GetValue(
                attribute, 
                System.Reflection.BindingFlags.GetField, 
                null, 
                null, 
                Thread.CurrentThread.CurrentUICulture);



При этом без использования параметра culture конвертера (зачем он нужен? - я же и так в функцию GetValue передаю нужную мне культуру. Да и почему-то под дебагом видно, что культура в параметре конвертера всё равно стоит en-US.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126682
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я ещё не уверен в правильности установки всех параметров этого варианта функции GetValue, но вроде, почитав в МСДНе, всё верно сделал.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126685
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, и при этом, если под дебагом посмотреть, на момент вызова GetValue значение Thread.CurrentThread.CurrentUICulture равно ru-RU, как я и установил в конструкторе приложения.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126686
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, забыл сказать, что проблема в том, что в интерфейсе показывает для Name-свойства атрибута значеие ExceedThresholdName вместо локализованной строки.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38126697
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И ещё я забыл сказать, что у меня пока и модели, и ресурсы для модели, и модели представления в одной сборке находятся. И ещё дефолтная культура у меня в Виндовс стоит английская. Может, в этом дело, что у меня параметр culture конвертера английский?

Но по идее, это не должно влиять на выбор строки из ресурсов в функции GetValue - ведь там я передал культуру какую надо.
...
Рейтинг: 0 / 0
Атрибуты свойств модели - через модель представления - привязать к представлению - как?
    #38127199
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
О, нашёл ошибку! Вот это да! Почему-то DisplayAttribute не ищет значения в ресурсах, а просто выдаёт то, что ему в свойстве Name написали. Написал я там ключ из словаря ресурсов, а он не ищет значение по этому ключу, а просто название этого ключа и выводит.

Я написал свой атрибут


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class LocalizedDisplayAttribute : Attribute
{
	private readonly string name;

	public LocalizedDisplayAttribute(string name)
		: base()
	{
		this.name = name;
	}

	public virtual string Name
	{
		get
		{
			var rm = new System.Resources.ResourceManager(typeof(WpfApplication1.Resources.Models.Settings.Common.Locals.Strings));
			return rm.GetString(this.name);
		}
	}
}



И использую его так

Код: c#
1.
2.
[LocalizedDisplay("ExceedThresholdName")]
public double ExceedThreshold { get; set; }




И всё работает!

Почему скотина DisplayAttribute так себя ведёт? Ведь написано же, что он специально сделан, чтобы по локализованные значения искать. И главное, у меня в проекте на ASP.NET MVC он работает.
...
Рейтинг: 0 / 0
23 сообщений из 23, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Атрибуты свойств модели - через модель представления - привязать к представлению - как?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]