Следуя шаблону MVVM, как создать функцию «Настройки», которая устанавливает значения элемента с привязкой к данным в других пользовательских элементах управления? - PullRequest
0 голосов
/ 10 мая 2018

!! Пожалуйста, смотрите вторую правку внизу первой!

Упрощенная версия моей проблемы: у меня есть два простых пользовательских элемента управления Apple и Banana (представление) с соответствующими им моделями представления, содержащими по 2 свойства в каждом. У меня также есть ListBox в качестве «Настройки» свойств Apple и Banana.

Apple:

<UserControl>  
    <StackPanel Orientation="Horizontal">  
        <TextBlock Margin="0,0,20,0" Text="{Binding AppleID}"/>  
        <TextBlock Text="{Binding Size}"/>  
    </StackPanel>  
</UserControl>  

Banana:

<UserControl>  
    <StackPanel Orientation="Horizontal">
        <TextBlock Margin="0,0,20,0"  Text="{Binding BananaID}"/>
        <TextBlock Text="{Binding Length}"/>
    </StackPanel>
</UserControl>  

Apple VM:

public class AppleViewModel : Notifier
{
    private string appleID;
    public string AppleID
    {
        get => appleID; set
        {
            appleID = value;
            OnPropertyChanged("AppleID");
        }
    }
    private int size;
    public int Size
    {
        get => size; set
        {
            size = value;
            OnPropertyChanged("Size");
        }
    }
}

Банановая ВМ:

public class BananaViewModel : Notifier
{
    private string bananaID;
    public string BananaID
    {
        get => bananaID; set
        {
            bananaID = value;
            OnPropertyChanged("BananaID");
        }
    }
    private int length;
    public int Length
    {
        get => length; set
        {
            length = value;
            OnPropertyChanged("Length");
        }
    }
}

Главное окно выглядит так:

<Window>
    <StackPanel Orientation="Vertical">
        <local:AppleControlxaml x:Name="apple"/>
        <local:BananaControl x:Name="banana"/>
        <ListBox>

        </ListBox>
    </StackPanel>
</Window>

Для более быстрой настройки я назначил DataContext в коде в главном окне. В реальной ситуации я использовал вместо окна viewmodel.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        apple.DataContext = new AppleViewModel()
        {
            AppleID = "Apple001",
            Size = 10,
        };
        banana.DataContext = new BananaViewModel()
        {
            BananaID = "Banana002",
            Length = 10
        };
    }
}

А теперь я хочу, чтобы элемент управления listBox отображал и позволял пользователю устанавливать значения свойств фокусируемого пользовательского элемента управления. Типичным взаимодействием может быть область управления пользователями Apple Select / Mousedown -> Изменить длину в списке -> Видеть, что значения пользовательских элементов управления Apple изменились.

И если пользователь выбирает / отключает пользовательский элемент управления Banana, он / она должен делать то же самое.

Вопрос в том, как реализовать эту функцию настроек с помощью MVVM и привязки данных? Я пытался создать ObservableCollection для привязки ItemsSource окна просмотра, но как убедиться, что коллекция корректно обновляет модель представления Apple?

Извините за длинный пост. Я довольно новичок в stackoverflow.


Второе редактирование

Мои извинения, но моё описание могло сделать проблему более запутанной. Свойства должны использовать ItemsControl вместо ListBox. Вот желаемое поведение. Пользовательский интерфейс, когда пользовательским элементом управления apple является MouseDown Пользовательский интерфейс, когда пользовательским элементом управления banana является MouseDown

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

Я подозреваю, что мне следует привязать данные свойства ItemsSource в ItemControl Properties к фактическим свойствам AppleVM и BananaVM, но я не уверен, как правильно это сделать, используя привязку данных.

Вот обновленный файл MainWindow.xaml. Другие коды практически не изменились с первого редактирования

<Window>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <StackPanel>
            <local:AppleControl x:Name="apple1" MouseDown="apple1_MouseDown"/>
            <local:BananaControl x:Name="banana1" MouseDown="banana1_MouseDown"/>
        </StackPanel>
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Text="Properties of selected item" Foreground="Blue" Margin="10"></TextBlock>
            <ItemsControl Name="properties" Grid.Row="1" Margin="10">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding PropertyName}"/>
                            <TextBlock Text="{Binding PropertyValue}"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Grid>
    </Grid>
</Window>

1 Ответ

0 голосов
/ 11 мая 2018

Я дам вам мою идею в соответствии с тем, что я понял из вашего вопроса.

MainWindow.xaml.cs

    public partial class MainWindow : Window
{
    private AppleViewModel appleViewModel;
    public AppleViewModel AppleViewModel
    {
        get
        {
            return this.appleViewModel;
        }
        set
        {
            if (this.appleViewModel != value)
            {
                this.appleViewModel = value;
            }
        }
    }

    private BananaViewModel bananaViewModel;
    public BananaViewModel BananaViewModel
    {
        get
        {
            return this.bananaViewModel;
        }
        set
        {
            if (this.bananaViewModel != value)
            {
                this.bananaViewModel = value;
            }
        }
    }


    public MainWindow()
    {
        InitializeComponent();

        this.AppleViewModel = new AppleViewModel();
        this.AppleViewModel.AppleID = "Apple001";
        this.AppleViewModel.Size = 10;

        this.BananaViewModel = new BananaViewModel();
        this.BananaViewModel.BananaID = "Banana001";
        this.BananaViewModel.Length = 10;

        apple.DataContext = this.AppleViewModel;

        banana.DataContext = this.BananaViewModel;

        ObservableCollection<int> sizes = new ObservableCollection<int>();
        for (int i = 0; i < 10; i++)
        {
            sizes.Add(i);
        }

        ListBox.ItemsSource = sizes;

    }

    private void ListBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (this.AppleViewModel.IsSelected)
        {
            this.AppleViewModel.Size = (int)ListBox.SelectedItem;
        }
        if (this.BananaViewModel.IsSelected)
        {
            this.BananaViewModel.Length = (int)ListBox.SelectedItem;
        }
    }
}

MainWindow.xaml

 <StackPanel Orientation="Vertical">
        <wpfApplication4:AppleControlxaml x:Name="apple"/>
        <wpfApplication4:BananaControl x:Name="banana"/>
        <ListBox SelectionChanged="ListBox_OnSelectionChanged" x:Name="ListBox">
        </ListBox>
    </StackPanel>

Ваши виртуальные машины с фруктами должны иметь новое свойство IsSelected, например:

private bool isSelected;
    public bool IsSelected
    {
        get
        {
            return this.isSelected;

        }
        set
        {
            this.isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }

И ваш контроль фруктов должен иметь это тоже

<CheckBox IsChecked="{Binding IsSelected}"/>

Если вы не хотите использовать этот флажок, просто скажите мне, и я постараюсь найти более точный ответ


Изменить для уточнения вашего редактирования (xD):

Допустим, вы уже создали свой "SettingsVM" с его свойствами Value и Description. Теперь вы хотите показать выбранные настройки фруктов в вашем ListBox. Итак, начнем... Каждый раз, когда ваш фрукт меняется, свойства вашего SettingsVM тоже должны меняться, чтобы показать нужный фрукт. В вашем "banana1_MouseDown" или "apple1_MouseDown" вы должны инициализировать ваши SettingsVM с их свойствами, чтобы вы могли создать метод для этого.

private void InitializeSettingsVM(int value, string description)
    {
      //Same like you do when you initialize your Banana/AppleVM in your MainWindow initialize.
      this.SettingsVM.Value = value;
      this.SettingsVM.Description = description;
    }

В вашем banana1_MouseDown / apple1_MouseDown вы должны сделать:

private void banana1_MouseDown(whateveryouhavehere)
   {
     //Whatever you do here
     this.InitializeSettingsVM(this.BananaViewModel.Length,this.BananaViewModel.BananaID);
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...