代码之家  ›  专栏  ›  技术社区  ›  mumoryan

遵循MVVM模式,如何创建一个“设置”函数来设置其他用户控件中的数据绑定项值?

  •  0
  • mumoryan  · 技术社区  · 7 年前

    !!请首先查看底部的第二次编辑!

    我的问题的简化版本:我有两个简单的用户控件Apple和Banana(视图),它们对应的视图模型分别包含2个属性。我还有一个列表框作为苹果和香蕉属性的“设置”。

    苹果公司:

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

    苹果虚拟机:

    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。在实际情况中,我使用了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控件能够显示并允许用户设置所关注的用户控件的属性值。典型的交互方式是选择/鼠标向下移动Apple用户控制区->更改列表框中的长度->查看apple用户控件值已更改。

    如果用户选择/mousedown Banana用户控件,他/她也应该能够这样做。

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

    抱歉发了这么长的帖子。我是stackoverflow的新手。


    第二次编辑

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

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

    我怀疑应该将属性的ItemControl中的ItemsSource属性与AppleVM和BananaVM的实际属性进行数据绑定,但我不确定如何使用数据绑定正确地做到这一点。

    这是更新后的主窗口。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 回复  |  直到 7 年前
        1
  •  0
  •   Juan Carlos Rodriguez    7 年前

    根据我从你的问题中了解到的情况,我会告诉你我的想法。

    主窗口。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;
            }
        }
    }
    

    主窗口。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”。现在,您希望在列表框中显示选定的水果设置。所以我们走吧。。。 每次你的水果改变,你的设置SVM的属性也必须改变,以显示正确的水果。在“banana1\u MouseDown”或“apple1\u MouseDown”中,您必须使用其属性初始化设置SVM,以便创建一个方法来执行此操作。

    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\u MouseDown/apple1\u MouseDown中,您应该执行以下操作:

    private void banana1_MouseDown(whateveryouhavehere)
       {
         //Whatever you do here
         this.InitializeSettingsVM(this.BananaViewModel.Length,this.BananaViewModel.BananaID);
       }