遵循MVVM模式,如何创建“设置”功能,在其他用户控件中设置数据绑定项值?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了遵循MVVM模式,如何创建“设置”功能,在其他用户控件中设置数据绑定项值?相关的知识,希望对你有一定的参考价值。

!!请先看看底部的第二个编辑!

我的问题的简化版本:我有两个简单的用户控件Apple和Banana(view)及其相应的视图模型,每个模型包含2个属性。我还有一个ListBox作为Apple和Banana属性的“设置”。

苹果:

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

香蕉:

<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");
        }
    }
}

香蕉VM:

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>

为了更快地进行设置,我在mainwindow中的代码中分配了DataContext。在实际情况中,我使用了window 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控件显示并允许用户设置被聚焦的用户控件的属性值。典型的交互将是Select / Mousedown Apple用户控制区域 - >更改列表框中的长度 - >查看Apple用户控件值已更改。

如果用户选择/ mousedown香蕉用户控制,他/她应该能够做同样的事情。

问题是:如何使用MVVM和数据绑定实现此设置功能?我尝试为要绑定的视图框的ItemsSource创建一个ObservableCollection,但是如何确保集合正确更新apple视图模型?

对不起,很长的帖子。我是stackoverflow的新手。


第二次编辑

我很抱歉,但我的描述可能会使问题更加混乱。属性应使用ItemsControl而不是ListBox。这是期望的行为。 The UI when apple user control is MouseDown The UI when banana user control is MouseDown

当用户更改属性中的值时,用户控件(苹果或香蕉)也应更新其值。

我怀疑我应该将Properties的ItemControl中的ItemsSource属性数据绑定到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>
答案

我会根据你的问题理解我的想法。

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):

假设您已经使用其Value及其Description属性创建了“SettingsVM”。现在,您要在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);
   }

以上是关于遵循MVVM模式,如何创建“设置”功能,在其他用户控件中设置数据绑定项值?的主要内容,如果未能解决你的问题,请参考以下文章

MVVM 模式中代码隐藏的实用使用

在 MVVM 设计模式中,模型是不是应该包含其他模型?

登录后如何在 SwiftUI 中显示新视图

WPF MvvM DataGrid 动态列

Angular 设计模式:MVC、MVVM 还是 MV*?

如何在WPF中动态创建布局(MVVM模式)