DataBinding在MVVM模式中使用combobox的问题。 [英] DataBinding Issue with combobox in MVVM pattern.

查看:58
本文介绍了DataBinding在MVVM模式中使用combobox的问题。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MVVM开发WPF技术。我在绑定组合框时遇到问题。有一对多的关系。当我选择单个值时,我想在组合框中加载相关值。

***There is one to many relationship. When I select the single value i want to load related values in combo box***

**Following is view Model**


       using System;
       using System.Collections.Generic;
       using System.Collections.ObjectModel;
       using System.Linq;
       using System.Text;
       using System.Threading.Tasks;
       using Homeopathic_Healing_Zone.Data;
       using Homeopathic_Healing_Zone.Desktop.Services;

    namespace Homeopathic_Healing_Zone.Desktop.PatientSign

    {
      class EditPatientSignViewModel : BindableBase
        {
    
            private ISignRepository _repo;
            
            public EditPatientSignViewModel(ISignRepository repo)
            {
                _repo = repo;
               
            }
    
            private ObservableCollection<SignsValue> _signsValues;
    
            public ObservableCollection<SignsValue> SignsValue
            {
                get { return _signsValues; }
                set { SetProperty(ref _signsValues, value); }
            }
    
            private SignsValue _selectSignsValue;
    
            public SignsValue selectSignsValue
            {
                get { return _selectSignsValue; }
                set { SetProperty(ref _selectSignsValue, value); }
            }
    
    
            private SimpleEditableSign _sign;
    
            public SimpleEditableSign Sign
            {
                get { return _sign; }
                set { SetProperty(ref _sign, value); }
            }
    
            private Sign _editingSign = null;
    
            
            public void SetSign(Sign sin)
            {
                _editingSign = sin;
                if (Sign != null) Sign.ErrorsChanged -= RaiseCanExecuteChanged;
                Sign = new SimpleEditableSign();
                Sign.ErrorsChanged += RaiseCanExecuteChanged;
                CopySign(sin, Sign);
            }
    
            private void RaiseCanExecuteChanged(object sender, EventArgs e)
            {
                SaveCommand.RaiseCanExecuteChanged();
            }
    
    
            private async void OnSave()
            {
                UpdateSign(Sign, _editingSign);
    
                await _repo.AddSignAsync(_editingSign);
    
               // System.Threading.Thread.Sleep(5000);
    
                //Done();
    
    
            }
    
    
            private bool CanSave()
            {
                return !Sign.HasErrors;
                // return true;
            }
    
    
            private void OnCancel()
            {
                Done();
            }
    
    
            private async void CopySign(Sign source, SimpleEditableSign target)
            {
                target.Id = source.SignId;
    
    
                target.Name = source.Name;
    
    
                //target.ValueName = source.SignsValues.Equals(target.Id, 
                  source.SignId);
                //var x = source.SignsValues.Where(v => v.SignId == 
                   target.Id).ToString();
    
                  SignsValue = new ObservableCollection<SignsValue>(
                    await _repo.GetSignsWithSignsValuesAsync(source.SignId)
                );
               
            }
    
            
    
            public  void LoadSignValues(Sign a)
            {
    
                
            }
        }
    }
**following is xmal file of view**


    <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:local="clr-namespace:Homeopathic_Healing_Zone.Desktop.PatientSign"
                 xmlns:Data="clr-namespace:Homeopathic_Healing_Zone.Data;assembly=Homeopathic-Healing-Zone.Data"
                 x:Class="Homeopathic_Healing_Zone.Desktop.PatientSign.EditPatientSignView"
                 mc:Ignorable="d"
                 d:DesignHeight="450"
                 d:DesignWidth="800"
                 Loaded="UserControl_Loaded">
        

     <Grid >
            <Grid x:Name="Grid1"
                  DataContext="{Binding Sign}"
                  HorizontalAlignment="Left"
                  Margin="84,85,0,0"
                  VerticalAlignment="Top">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Label Content="Name:"
                       Grid.Column="0"
                       HorizontalAlignment="Left"
                       Margin="3"
                       Grid.Row="0"
                       VerticalAlignment="Center" />
                <TextBox x:Name="NameTextBox"
                         Grid.Column="1"
                         HorizontalAlignment="Left"
                         Height="23"
                         Margin="3"
                         Grid.Row="0"
                         Text="{Binding Name, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
                         VerticalAlignment="Center"
                         Width="120" />
            </Grid>
    
            <ComboBox HorizontalAlignment="Left"
                      Margin="424,85,0,0"
                      VerticalAlignment="Top"
                      Width="159"
                      ItemsSource="{Binding}"
                      DisplayMemberPath="Name"
                      SelectedValuePath="SignId"
    
                      />
    
    
        </Grid>
    </UserControl>




推荐答案

Hi M.NISAR,

Hi M.NISAR,

这里有一个简单的例子演示如何同步两个组合框,考虑一下以下ViewModel:

here is a simple example demonstrating how to synchronize two combo box, consider the following ViewModel:

namespace OneToManyComboBox
{
    public class Parent
    {
        public int ParentId { get; set; }
        public string Name { get; set; }
        public List<Child> Many { get; set; }
    }

    public class Child
    {
        public int ChildId { get; set; }
        public int ParentId { get; set; }
        public string Name { get; set; }
    }
    public class MainWindowViewModel: ObservableObject
    {
        public ObservableCollection<Parent> Parents { get; set; }

        public MainWindowViewModel()
        {
            Parents = new ObservableCollection<Parent>(new List<Parent>() {
                new Parent
                { ParentId=1, Name="test1",
                    Many = new List<Child>
                    {
                        new Child{ ChildId = 1, Name = "Parent1-Child1", ParentId = 1},
                        new Child{ ChildId = 2, Name = "Parent1-Child2", ParentId = 1},
                        new Child{ ChildId = 3, Name = "Parent1-Child3", ParentId = 1}
                    }
                },
                new Parent
                { ParentId=1, Name="test2",
                    Many = new List<Child>
                    {
                        new Child{ ChildId = 1, Name = "Parent2-Child1", ParentId = 2},
                        new Child{ ChildId = 2, Name = "Parent2-Child2", ParentId = 2},
                        new Child{ ChildId = 3, Name = "Parent2-Child3", ParentId = 2}
                    }
                }
            });
        }
    }
}

此视图的XAML:

<Window x:Class="OneToManyComboBox.MainWindow"
    ....>
    <Window.DataContext>
        <local:MainWindowViewModel x:Name="vm"/>
    </Window.DataContext>
    <Grid>
        <ComboBox x:Name="ParentsCombobox" HorizontalAlignment="Left" Margin="30,90,0,0" VerticalAlignment="Top" Width="120" 
                  ItemsSource="{Binding Parents}" DisplayMemberPath="Name">
        </ComboBox>
        <ComboBox HorizontalAlignment="Left" Margin="176,90,0,0" VerticalAlignment="Top" Width="120" 
                  ItemsSource="{Binding ElementName=ParentsCombobox, Path= SelectedItem.Many}" 
                  DisplayMemberPath="Name"/>

    </Grid>
</Window>

查看两个组合框上ItemsSource的绑定:

take a look at the bindings for the ItemsSource on the two combo boxes:

<ComboBox x:Name="ParentsCombobox"
          ItemsSource="{Binding Parents}" DisplayMemberPath="Name">
</ComboBox>
<ComboBox 
          ItemsSource="{Binding ElementName=ParentsCombobox, Path= SelectedItem.Many}" 
          DisplayMemberPath="Name"/>


 

这假设每个父母都包含相关孩子的列表(比如说
DDD中的聚合根
),否则,逻辑应该被调整,并且将取决于将在SelectionChanged上触发的命令,让我们来看看ViewModel:

 

this assuming that each parent contains a list of related children (let say aggregate root in DDD), otherwise, the logic should be adapted, and will depend on a command that will be triggered on SelectionChanged, let's take a look to the ViewModel:

public class MainWindowViewModel: ObservableObject
{
    public ObservableCollection<Parent> Parents { get; set; }
    public ObservableCollection<Child> Many { get; set; }
    public DelegateCommand<Parent> ParentChangedCommand { get; set; }

    private List<Child> _related;

    public MainWindowViewModel()
    {
        _related = new List<Child>
        {
            new Child{ ChildId = 1, Name = "Parent1-Child1", ParentId = 1},
            new Child{ ChildId = 2, Name = "Parent1-Child2", ParentId = 1},
            new Child{ ChildId = 3, Name = "Parent1-Child3", ParentId = 1},
            new Child{ ChildId = 1, Name = "Parent2-Child1", ParentId = 2},
            new Child{ ChildId = 2, Name = "Parent2-Child2", ParentId = 2},
            new Child{ ChildId = 3, Name = "Parent2-Child3", ParentId = 2}
        };

        Parents = new ObservableCollection<Parent>(new List<Parent>() {
            new Parent { ParentId=1, Name="test1" },
            new Parent { ParentId=2, Name="test2" }
        });
            
        Many = new ObservableCollection<Child>(_related);

        ParentChangedCommand = new DelegateCommand<Parent>((p) => {
            Many = new ObservableCollection<Child>(_related.Where(c => c.ParentId == p.ParentId).ToList());
            RaisePropertyChanged(nameof(Many));
        });

    }
}




这一次我们有两个集合  只有ParentId作为子节点中的一个键,我们还有一个新的命令可以处理更改的父选择,这里是委托处理程序的代码:

this time we have two collections with just the ParentId as a key in the child one, also we have a new command which will handle the parent selection changed, here is the code for the delegate handler:

public class DelegateCommand<T> : ICommand 
    where T: class
{
    private Action<T> _action;
    private Func<T, bool> _predicate;

    public DelegateCommand(Action<T> action, Func<T, bool> predicate = null)
    {
        _action = action;
        _predicate = predicate;
    }

    public event EventHandler CanExecuteChanged;
    public bool CanExecute(object parameter)
    {
        return _predicate?.Invoke((T)parameter) ?? true;
    }

    public void Execute(object parameter)
    {
        _action.Invoke((T)parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, new EventArgs());
    }
}




最后一部分涉及使用表达式混合的交互命名空间:

the last part involves the usage of Interactivity namespace of expression blend:

Install-Package Microsoft.SDK.Expression.Blend

和Xaml你应该声明命名空间: 

and in the Xaml you should declare the namespace: 

<Window 
    ....
    xmlns:i="clr-namespace:System.Windows.Interactivity;namespace=System.Windows.Interactivity"
    ....>


    <Window.DataContext>
        <local:MainWindowViewModel x:Name="vm"/>
    </Window.DataContext>
    <Grid>
        <ComboBox x:Name="ParentsCombobox" HorizontalAlignment="Left" Margin="30,90,0,0" VerticalAlignment="Top" Width="120" 
                  ItemsSource="{Binding Parents}" DisplayMemberPath="Name">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding ParentChangedCommand}" CommandParameter="{Binding ElementName=ParentsCombobox, Path=SelectedItem}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
        <ComboBox HorizontalAlignment="Left" Margin="176,90,0,0" VerticalAlignment="Top" Width="120" 
                  ItemsSource="{Binding Many, Mode=TwoWay,BindsDirectlyToSource=True}" 
                  DisplayMemberPath="Name"/>

    </Grid>

Expression Blend Interactivity库让我们可以在框架元素上使用触发器和行为。

the Expression Blend Interactivity library gives us the possibility to use triggers and behaviors on framework elements.

最诚挚的问候,

Mouad。

良好的编码;








这篇关于DataBinding在MVVM模式中使用combobox的问题。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆