Как я могу использовать массив в ViewModel? - PullRequest
0 голосов
/ 22 октября 2018

Мой код выглядит сейчас так, с двумя строками кода для каждого сообщения.Код работает, но если у меня есть, например, 30 сообщений, каждое из которых я могу дать значения, то мне нужно будет 60 строк кода, чтобы просто объявить все:

string _msg1;
string _msg2;
public string Msg1 { get => _msg1; set => SetProperty(ref _msg1, value); }
public string Msg2 { get => _msg2; set => SetProperty(ref _msg2, value); }

и в C # я назначаю им:

vm.Msg1 = "A";
vm.Msg2 = "B"; 

и в XAML я связываю свой текст с Msg1, а другой текст с Msg2

Может кто-нибудь сказать мне, как / если я могу сделать это с массивом, чтобы я мог назначить вот таки, надеюсь, что присвоение массива может быть сделано в две строки вместо двух строк для каждого отдельного сообщения:

vm.Msg[0] = "A";
vm.Msg[1] = "B";

Для справки:

public class ObservableObject : INotifyPropertyChanged
{

    protected virtual bool SetProperty<T>(
        ref T backingStore, T value,
        [CallerMemberName]string propertyName = "",
        Action onChanged = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value))
            return false;

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}

Ответы [ 5 ]

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

Не совсем уверен, что я получил вопрос, но, как я понял, самый простой способ заключается в следующем:

Viewmodel:

Просто связать с ObservableCollection строк, потому что это ужереализует INotifyCollectionChanged и INotifyPropertyChanged.RelayCommand - это просто реализация ICommand, и я предполагаю, что вы слышали о них с тех пор, как запускаете WPF MVVM.

using System.Collections.ObjectModel;

namespace WpfApp1
{
    public class MainWindowViewmodel
    {
        public ObservableCollection<string> Messages { get; set; }
        public MainWindowViewmodel()
        {
            Messages = new ObservableCollection<string>();
            Messages.Add("My message!");
            ChangeMessageCommand = new RelayCommand(ChangeMessageExcecute); 
        }
        public RelayCommand ChangeMessageCommand { get; set; }
        private void ChangeMessageExcecute() => Messages[0] = "NEW message!";
    }
}

Вид:

В представлении, которое выможете просто связать свой Textblocks с Elements из ObservableCollection.Когда вы нажимаете кнопку, вызывается Command и изменяется сообщение в окне.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Messages[0]}" HorizontalAlignment="Center"/>
            <Button Content="Change Message" Command="{Binding ChangeMessageCommand}" Width="200"/>
        </StackPanel>
    </Grid>
</Window>

С уважением, неправильное направление

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

Как насчет использования отражения?Вы можете запросить все открытые свойства типа string с именем «Msg *».

Например:

static class Program
{
    static void Main(string[] args)
    {
        var vm = new MessagesViewModel();

        PropertyInfo[] myProperties = vm.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.PropertyType == typeof(string) && p.Name.Contains("Msg"))
            .ToArray();

        foreach (var propertyInfo in myProperties)
        {
            //You can also access directly using the indexer --> myProperties[0]..
            propertyInfo.SetValue(vm, $"This is {propertyInfo.Name} property");
        }

        Console.WriteLine(vm.Msg1);
        Console.WriteLine(vm.Msg2);
    }
}

public class MessagesViewModel
{
    string _msg1;
    string _msg2;
    public string Msg1 { get => _msg1; set => _msg1 = value; }
    public string Msg2 { get => _msg2; set => _msg2 = value; }
}

Если подходит этот тип решения, вы можете заключить его в индексаторсортируйте массив в соответствии с индексом и Msg [num].

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

I Предполагаю, что данный пример работает и работает должным образом (Atleast с 2 элементами)

Просмотр Код .

Предполагая, что вы хотите показать все 30 сообщений в виде списка.

<ListView ItemsSource="{Binding MessagesArray}"/>

Также вы должны правильно установить DataContext, Комментарий нижеесли вам нужна помощь

Просмотр кода модели.

Мы используем ObservableCollection вместо массива,Поскольку чистые массивы не поддерживают надлежащие обязательные функции.

private ObservableCollection<string> _messagesArray;

public ObservableCollection<string> MessagesArray  
{  
    get { return _messagesArray; }  
    set { SetProperty(ref _messagesArray, value); }  
}  

Назначение значений

MessagesArray = new ObservableCollection<string>();
vm.MessagesArray.Add("A");
vm.MessagesArray.Add("B");

В коде присвоения MessagesArray = new ObservableCollection<string>(); назначается новый объект ObservableCollection из String

Если вы новичок в ObservableCollection, подумайте об этом как обертка для string[], но на самом деле это не так * Метод 1045 *

SetProperty будетсообщите XAML View, что новая коллекция прибыла, поэтому пользовательский интерфейс будет повторно отображать список.

Когда вы вызываете vm.MessagesArray.Add("B"); внутреннюю логику внутри метода, Add сообщит XAML Вид, что новый элемент добавлен в ObservableCollection, так что представление может перерисовать ListView с новым элементом..

Обновление 27 октября 2018

Вы можете создать свой собственный массив, используя любым из указанными ниже способами.(Не все)

 string[] dataArray = new string[30];

1.это создаст массив с 30 нулевыми значениями

 string[] dataArray = { "A", "B", "C" }; //Go up to 30 items

2.это создаст массив с предопределенным набором значений, вы можете перейти к 30

 string[] dataArray = Enumerable.Repeat<string>(String.Empty, 30).ToArray();

3.это создаст массив со строкой, которая содержит пустые значения. Вместо String.Empty вы можете поместить любое строковое значение.

Выберите любой из вышеперечисленных методов

Я рекомендуюпоследний метод, затем вы можете назначить его в наблюдаемую коллекцию, как показано ниже.

MessagesArray = new ObservableCollection<string>(dataArray); 

Теперь уловка

vm.MessagesArray[0] = "A"
vm.MessagesArray[25] = "Z"

Вид может выглядеть следующим образом

<TextBlock Text="{Binding MessagesArray[0]}"/>
<TextBlock Text="{Binding MessagesArray[1]}"/>
0 голосов
/ 28 октября 2018

Можно создать простой класс-оболочку с индексированием , который поддерживает уведомление об изменении свойства .

Например:

public class Messages : ObservableObject
{
    readonly IDictionary<int, string> _messages = new Dictionary<int, string>();

    [IndexerName("Item")] //not exactly needed as this is the default
    public string this[int index]
    {
        get
        {
            if (_messages.ContainsKey(index))
                return _messages[index];

//Uncomment this if you want exceptions for bad indexes
//#if DEBUG
//          throw new IndexOutOfRangeException();
//#else
            return null; //RELEASE: don't throw exception
//#endif
        }

        set
        {
            _messages[index] = value;
            OnPropertyChanged("Item[" + index + "]");
        }
    }
}

И создать свойство в модели представленияas:

private Messages _msg;
public Messages Msg
{
    get { return _msg ?? (_msg = new Messages()); }
    set { SetProperty(ref _msg, value); }
}

Теперь вы можете установить или обновить значения следующим образом:

vm.Msg[0] = "A";
vm.Msg[1] = "B";

Привязки в XAML будут такими же, как:

<Label Text="{Binding Msg[0]}" />
<Label Text="{Binding Msg[1]}" />

Пример кода использования

XAML

<StackLayout Margin="20">
    <Label Text="{Binding Msg[0]}" />
    <Label Text="{Binding Msg[1]}" />
    <Label Text="{Binding Msg[2]}" />
    <Label Text="{Binding Msg[3]}" />
    <Label Text="{Binding Msg[4]}" />

    <Button Text="Trigger update" Command="{Binding UpdateMessage}" />
</StackLayout>

Кодовый код, модель просмотра

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        var viewModel = new MainViewModel();

        viewModel.Msg[0] = "Original message 1";
        viewModel.Msg[1] = "Original message 2";
        viewModel.Msg[2] = "Original message 3";
        viewModel.Msg[3] = "Original message 4";
        viewModel.Msg[4] = "Original message 5";

        BindingContext = viewModel;
    }
}

public class MainViewModel : ObservableObject
{
    private Messages _msg;
    public Messages Msg
    {
        get { return _msg ?? (_msg = new Messages()); }
        set { SetProperty(ref _msg, value); }
    }

    public ICommand UpdateMessage => new Command(() =>
           {
               Msg[2] = "New message 3";
               Msg[0] = "New message 1";
           });
}

enter image description here

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

Массивы не будут вызывать событие изменения свойства.Вам нужно будет использовать ObservableCollection, который может вызвать событие, когда коллекция изменилась.Однако это не вызывает событие, когда объект внутри коллекции изменил свое значение.Вам нужно будет обернуть ваш объект, в данном случае строку, в тип, который может вызывать события изменения свойств.

Будет работать что-то вроде следующего:

    public class BindableValue<T> : INotifyPropertyChanged
    {
        private T _value;
        public T Value
        { get => _value; set => SetProperty(ref _value, value); }
        // INotifyPropertyChanged and SetProperty implementation goes here
    }

    private ObservableCollection<BindableValue<string>> _msg;
    public ObservableCollection<BindableValue<string>> Msg
    { get => _msg; set => SetProperty(ref _msg1, value); }

вы будетепривязка к Msg[0].Value, Msg[1].Value и т. д.,

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