【问题标题】:WPF MVVM Populate combobox OnPropertyChanged of another comboboxWPF MVVM 填充组合框 OnPropertyChanged 的​​另一个组合框
【发布时间】:2014-03-19 03:34:32
【问题描述】:

我想在combobox1 选择更改事件后填充我的combobox2。

这是我的 XAML 的一部分:

<ComboBox Name="cmbWorkcode"
        ItemsSource="{Binding Workcodes}" 
        DisplayMemberPath="WorkcodeName" 
        SelectedValuePath="WorkcodeID" 
        SelectedValue="{Binding Path=WorkcodeId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<ComboBox Name="cmbProcess" 
        ItemsSource="{Binding Processes}"
        DisplayMemberPath="ProcessName" SelectedValuePath="ProcessId"
        SelectedValue="{Binding Path=ProcessId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

我的 ViewModel 的某些部分:

class MainWindowViewModel : ObservableObject 
{
    private ObservableCollection<Workcode> _workcodes = new ObservableCollection<Workcode>();
    public ObservableCollection<Workcode> Workcodes
    {
        get { return _workcodes; }
        set
        {
            _workcodes = value;
            OnPropertyChanged("Workcodes");
        }
    }

    private int _workcodeId;
    public int WorkcodeId
    {
        get { return _workcodeId; }
        set
        {
            _workcodeId = value;
            OnPropertyChanged("WorkcodeId");
        }
    }

    private ObservableCollection<Process> _processes = new ObservableCollection<Process>();
    public ObservableCollection<Process> Processes
    {
        get { return _processes; }
        set
        {
            _processes = value;
            OnPropertyChanged("Processes");
        }
    }

    private int _processId;
    public int ProcessId
    {
        get { return _processId; }
        set
        {
            _processId = value;
            OnPropertyChanged("ProcessId");
        }
    }

    public MainWindowViewModel()
    {
        PopulateWorkcode();
    }

    private void PopulateWorkcode()
    {
        using (var db = new DBAccess())
        {
            db.ConnectionString = ConfigurationManager.ConnectionStrings["connString"].ConnectionString;
            db.Query = @"SELECT workcodeId, workcode FROM workcode";
            DataTable data = db.GetData();
            if (data != null)
            {
                foreach (DataRow row in data.Rows)
                {
                    int workcodeId = Convert.ToInt32(row["workcodeId"].ToString());
                    string workcodeName = row["workcode"].ToString();
                    _workcodes.Add(new Workcode(workcodeId, workcodeName));
                }
            }
        }    
    }

    private void PopulateProcess()
    {
        using (var db = new DBAccess())
        {
            db.ConnectionString = ConfigurationManager.ConnectionStrings["connString"].ConnectionString;
            db.Query = @"SELECT ProcessId, ProcessName FROM `process` WHERE WorkcodeId = @workcodeId";
            DataTable data = db.GetData(new[] {new MySqlParameter("@workcodeId", _workcodeId.ToString())});
            if (data != null)
            {
                foreach (DataRow row in data.Rows)
                {
                    int id = Convert.ToInt32(row["ProcessId"].ToString());
                    string name = row["ProcessName"].ToString();
                    _processes.Add(new Process(id, name));
                }
            }
        }
    }
}

我的问题是我不知道在哪里触发我的 PopulateProcess() 方法,以便我的 combobox2 将根据 combobox1 的选择来填充。感谢所有的时间和帮助! :)

--编辑--

public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Workcode
{
    public int WorkcodeId { get; set; }
    public string WorkcodeName { get; set; }

    public Workcode(int id, string name)
    {
        WorkcodeId = id;
        WorkcodeName = name;
    }
}

【问题讨论】:

  • 能否请您出示您的 WorkCode 课程

标签: c# wpf mvvm


【解决方案1】:

最初第二个组合框是空的,在选择第一个组合框时改变只是填充进程

 private int _workcodeId;
 public int WorkcodeId
 {
   get { return _workcodeId; }
   set
   {
      _workcodeId = value;
      OnPropertyChanged("WorkcodeId");
      if(WorkcodeID>0) PopulateProcess();
   }
}

【讨论】:

  • 最初获取一个 processcollection 并存储在临时集合中,并根据选择的工作代码填充第二个组合框。
  • @jomsk1e 你的 Process 类是否实现了 INPC?如果没有,我相信您必须引发 CollectionChanged 事件,以便 WPF 知道您的集合中的项目已更改。 (如果实际集合本身已更改,您当前的代码将通知更改,而不是其中的项目)。查看此答案以了解详细信息。 stackoverflow.com/questions/8490533/…
  • @failedprogramming,请看我的编辑,我添加了我用来实现 INotifyPropertyChanged 的​​类。
【解决方案2】:

我可以理解您希望下一个组合框根据前一个值填充数据。由于我没有你的类型的类,我将举一个简单的例子,

class ItemListViewModel<T> : INotifyPropertyChanged where T : class
{
    private T _item;
    private ObservableCollection<T> _items;

    public ItemListViewModel()
    {
        _items = new ObservableCollection<T>();
        _item = null;
    }

    public void SetItems(IEnumerable<T> items)
    {
        Items = new ObservableCollection<T>(items);
        SelectedItem = null; 
    }

    public ObservableCollection<T> Items
    {
        get { return _items; }
        private set
        {
            _items = value;
            RaisePropertyChanged("Items");
        }
    }

    public T SelectedItem
    {
        get { return _item; }
        set
        {
            _item = value;
            RaisePropertyChanged("SelectedItem");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

然后拥有将绑定到视图的 DataContext 的主视图模型。让 Load 方法做你想做的事

class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel()
    {
        First = new ItemListViewModel<string>();
        Second = new ItemListViewModel<string>();
        Third = new ItemListViewModel<string>();

        First.PropertyChanged += (s, e) => Update(e.PropertyName, First, Second, LoadSecond);
        Second.PropertyChanged += (s, e) => Update(e.PropertyName, Second, Third, LoadThird);

        LoadFirst();
    }

    public ItemListViewModel<string> First { get; set; }
    public ItemListViewModel<string> Second { get; set; }
    public ItemListViewModel<string> Third { get; set; }

    private void LoadFirst()
    {
        First.SetItems(new List<string> { "One", "Two", "Three" });
    }
    private void LoadSecond()
    {
        Second.SetItems(new List<string> { "First", "Second", "Third" });
    }
    private void LoadThird()
    {
         Third.SetItems(new List<string> { "Firsty", "Secondly", "Thirdly" });
    }

    private void Update<T0, T1>(string propertyName, ItemListViewModel<T0> parent, ItemListViewModel<T1> child, Action loadAction)
        where T0 : class
        where T1 : class
    {
        if (propertyName == "SelectedItem")
        {
            if (parent.SelectedItem == null)
            {
                child.SetItems(Enumerable.Empty<T1>());
            }
            else
            {
                loadAction();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

在 XAML 中,

    <ComboBox ItemsSource="{Binding First.Items}" SelectedItem="{Binding First.SelectedItem}" />
    <ComboBox ItemsSource="{Binding Second.Items}" SelectedItem="{Binding Second.SelectedItem}" />
    <ComboBox ItemsSource="{Binding Third.Items}" SelectedItem="{Binding Third.SelectedItem}" />

【讨论】:

  • 感谢 Sajeetharan 的时间,您的示例可能也会对其他人有所帮助。 :)
【解决方案3】:

问题来了

<ComboBox Name="cmbWorkcode"
    ItemsSource="{Binding Workcodes}" 
    DisplayMemberPath="WorkcodeName" 
    SelectedValuePath="WorkcodeId" 
    SelectedValue="{Binding Path=WorkcodeId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

它应该是 WorkcodeId 而不是 WorkcodeID。休息一下,你可以试试 Nishanth 的回答

public int WorkcodeId
{
   get { return _workcodeId; }
   set
   {
   if(_workcodeId !=value)
  {
    _workcodeId = value;
    OnPropertyChanged("WorkcodeId");
    PopulateProcess();
  }
 }
}

【讨论】:

  • 就是这样!谢谢!我是一个傻瓜! :(
  • 这是一个很好的收获:)。当我们使用 ObservableCollection 时,我们不需要通知另一件事,因此不需要创建支持字段。只有 public ObservableCollection Processes{get;set;} 可以工作。虽然你需要在构造函数中初始化它。
猜你喜欢
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多