Универсальный класс ViewModel - PullRequest
0 голосов
/ 18 октября 2018

Моя цель - создать класс ViewModel, который принимает объект любого типа и разбивает его на ObservableCollection его полей, которые можно отображать и изменять в представлении.Я представляю себе поля, обернутые в FieldViewModel, который предоставляет свойство 'string FieldName', а также свойство 'Value объекта' и, возможно, Type.

class ViewModel : ViewModelBase
{
    public ViewModel(ref object instance)
    {
        foreach (var field in instance.GetType().GetFields())
        {
            Fields.Add(new FieldViewModel(instance, field));
        }
    }

    private ObservableCollection<FieldViewModel> _fields = new ObservableCollection<FieldViewModel>();
    public ObservableCollection<FieldViewModel> Fields
    {
        get { return _fields; }
        set
        {
            _fields = value;
            OnPropertyChanged();
        }
    }
}

Приведенный выше псевдокод являетсяпопытаться сообщить о своем намерении.Конечно, потребуется больше кода, чтобы определить, доступны ли поля только для чтения.Если это невозможно, как бы вы порекомендовали это сделать?Пожалуйста, сообщите.

ПРИМЕЧАНИЕ: мое конкретное приложение заботится только о полях, а не о свойствах.Я не создавал модели данных, которые я буду отображать в пользовательском интерфейсе.

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Я нашел способ, который работает для моих целей.Это может быть расширено и для работы со свойствами, и все еще требует правильной обработки ошибок для ввода текста пользователем.

public class ViewModel : ViewModelBase
{
    public ViewModel(object instance)
    {
        foreach (var field in instance.GetType().GetFields())
        {
            Fields.Add(new FieldViewModel(instance, field));
        }
    }

    private ObservableCollection<FieldViewModel> _fields = new ObservableCollection<FieldViewModel>();
    public ObservableCollection<FieldViewModel> Fields
    {
        get { return _fields; }
        set
        {
            _fields = value;
            OnPropertyChanged();
        }
    }
}

И FieldViewModel выглядит следующим образом ...

public class FieldViewModel : ViewModelBase
{
    private object _instance;
    private FieldInfo _fieldInfo;
    private Type _fieldType;

    public FieldViewModel(object instance, FieldInfo fieldInfo)
    {
        _instance = instance;
        _fieldInfo = fieldInfo;

        _fieldType = fieldInfo.FieldType;

        IsReadOnly = fieldInfo.IsInitOnly || fieldInfo.IsLiteral;
        FieldName = fieldInfo.Name;
        TypeName = fieldInfo.FieldType.Name;
    }


    private bool _IsReadOnly;
    public bool IsReadOnly
    {
        get { return _IsReadOnly; }
        private set
        {
            _IsReadOnly = value;
            OnPropertyChanged();
        }
    }


    private string _fieldName;
    public string FieldName
    {
        get { return _fieldName; }
        set
        {
            _fieldName = value;
            OnPropertyChanged();
        }
    }

    private string _typeName;
    public string TypeName
    {
        get { return _typeName; }
        set
        {
            _typeName = value;
            OnPropertyChanged();
        }
    }

    public object Value
    {
        get
        {
            return _fieldInfo.GetValue(_instance);
        }
        set
        {
            _fieldInfo.SetValue(_instance, Convert.ChangeType(value, _fieldType));
            OnPropertyChanged();
        }
    }
}

И использование выглядит как ...

Person personInstance = new Person
{
    Name = "automagically",
    Age = 25,
    Height = 185.2,
    IsMarried = false
};

ViewModel = new ViewModel(personInstance);

И представление ...

<ItemsControl ItemsSource="{Binding ViewModel.Fields}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>

                <TextBlock Text="{Binding FieldName}" />
                <TextBox Grid.Column="1" Text="{Binding Value}" IsReadOnly="{Binding IsReadOnly}"/>
                <TextBlock Grid.Column="2" Text="{Binding TypeName}" />
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Что выглядит так ...

I can't embed images yet...

0 голосов
/ 18 октября 2018

ObservableCollection ExpandoObjects может сделать это.В основном это словарь с некоторым синтаксическим сахаром - и уведомление INotifyPropertyChanged о каждом изменении для каждого ключа.Остальные должны были бы пройти через поля исходной модели с помощью отражения.

В идеале, однако, не стоит пытаться обойти Сильную типизацию.Этот класс существует, прежде всего, для обеспечения возможности взаимодействия со слабо типизированными веб-серверами и т.п.Сильный Typisaiton является одним из ваших самых больших друзей.Просто посмотрите на примеры PHP и JavaScript из этого комикса, чтобы понять почему: http://www.sandraandwoo.com/2015/12/24/0747-melodys-guide-to-programming-languages/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...