在单个表单中使用MVVM和多个控件

时间:2013-10-28 14:29:29

标签: c# wpf mvvm combobox

我是WPF新手并开始学习MVVM概念。

我正在开发一个创建图形对象的应用程序,该图形对象包含来自数据库的数据。

我有一个包含多个标签和组合框的组框。

每个人都应该保留一份来自我的数据库的列表。

对于第一个组合框,我设法使用MVVVM填充该特定列表。

但是如果我已经使用第一个列表启动DataContext,我怎么能填充其他组合框?

我应该为每个ComboBox创建一个ModelView吗?

一般来说,如何动态地将几个组合框绑定到列表?

<Label Grid.Row="0"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiNam">Test Item Name :</Label>
<TextBox Grid.Row="0"
         Grid.Column="2"
         Name="tbTiName"
         MinWidth="100"
         MaxWidth="100"></TextBox>
<Label Grid.Row="1"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiExStat">Execution Status :</Label>
<ComboBox Grid.Row="1"
          Grid.Column="2"
          x:Name="cbTiExStat"
          MinWidth="100"
          MaxWidth="100"
          SelectedValuePath="Content"
          ItemsSource="{Binding Binding QcLists.FieldList}"
          DisplayMemberPath="Name">

</ComboBox>
<Label Grid.Row="2"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiVersion">Version :</Label>
<ComboBox Grid.Row="2"
          Grid.Column="2"
          Name="cbTiVersion"
          MinWidth="100"
          MaxWidth="100"
          SelectedValuePath="Content"
          SelectedIndex="1">
  <ComboBoxItem>To BE Bind From QC</ComboBoxItem>
</ComboBox>
<Label Grid.Row="3"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiCRID">CRID :</Label>
<ComboBox Grid.Row="3"
          Grid.Column="2"
          Name="cbTiCRID"
          MinWidth="100"
          MaxWidth="100"
          SelectedValuePath="Content">
  <ComboBoxItem>To BE Bind From QC</ComboBoxItem>
</ComboBox>
<Label Grid.Row="4"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiApplication">Application :</Label>
<ComboBox Grid.Row="4"
          Grid.Column="2"
          Name="cbTiApplication"
          MinWidth="100"
          MaxWidth="100"
          SelectedValuePath="Content">
  <ComboBoxItem>To BE Bind From QC</ComboBoxItem>
</ComboBox>
<Label Grid.Row="5"
       Grid.Column="0"
       Grid.ColumnSpan="2"
       Name="lblTiTestLevel">Test Level :</Label>
<ComboBox Grid.Row="5"
          Grid.Column="2"
          Name="cbTiTestLevel"
          MinWidth="100"
          MaxWidth="100"
          SelectedValuePath="Content">
  <ComboBoxItem>To BE Bind From QC</ComboBoxItem>
</ComboBox>

即时编辑我的qustion以添加更多信息:

内部类TestableItemViewModel {       公共QCLists QcLists         {             get {return _qcLists; }         }

    #endregion

   #region Constructor
    public TestableItemViewModel()
    {
        _qcconnect = QCConnection.QCConnect.getInstance();
       // LoadListSettings();
        LoadListSettings( "TS_USER_05");
        SaveCommand = new TestableItemSaveDetailsCommand(this);
    }
    #endregion

    private void LoadListSettings(String FieldName)
    {
        Customization cust = QCConnection.QCConnect.getInstance().GetTD.Customization;
        CustomizationFields fields = cust.Fields;
        CustomizationListNode node;
        CustomizationField field;
        field = fields.get_Field("TEST", FieldName);
        node = field.List.RootNode;
        _qcLists = new QCLists(node.Children, node.Name);
    }

}

class QCLists:INotifyPropertyChanged
{
    TDAPIOLELib.List _fieldList;
    List<String> myTestList;
    String listName;

    public String ListName
    {
        get { return listName; }
        set { listName = value; }
    }

    public List<String> MyTestList
    {
        get { return myTestList; }
        set { myTestList = value; }
    }

    public QCLists(TDAPIOLELib.List List,String name)
    {
        _fieldList = List;
        myTestList = new List<String>();
        listName = name;
    }

    public TDAPIOLELib.List FieldList
    {
        get
        {
            return _fieldList;
        }

        set
        {
            _fieldList = value;
            OnPropertyChanged("FieldList");

        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

    }

}

以及上面xaml背后的代码:

 DataContext = new TestableItemViewModel();

这些是我用过的课程。 正如你在我的xaml中看到的那样,第一个combocox绑定到requierd列表,我可以看到 我期望的价值观。 我如何保持绑定其他组合框? 因为我只有一个TestableItemViewModel实例已经绑定到第一个列表,而数据上下文正在使用该列表。 我有其他列表(实际上是4个),我需要绑定到其他控件。 当然,我使用查询获取requierd列表,但这是另一个问题,因为列表名称可以在任何给定的时间更改。 现在我只需要解决5绑定问题。

4 个答案:

答案 0 :(得分:2)

在MVVM范例中绑定组合框 - 您应该向ViewModel类添加一个列表,并使用要在组合框中显示的项目填充它。让我用一个例子来解释:

ViewModel中的

(应该实现INotifyPropertyChanged接口):

public BindingList<string> Cities { get; set; } 

由于您说从数据库中加载了组合框的值,因此您需要确保在值完成加载时在“Cities”上引发PropertyChanged - 这样视图就知道刷新任何绑定的东西财产“城市”。

在视图中:

<Combobox ItemsSource="{Binding Cities}" />

答案 1 :(得分:1)

答案是在WPF和MVVM中,我们设置各个控件的DataContext。相反,我们有一个视图模型类的实例,它具有我们需要在UI中显示的所有属性,我们将 设置为DataContext的{​​{1}}或查看。

通过这种方式,所有控件都可以访问视图模型中的所有属性,因此我们只需将每个控件的UserControl属性设置为视图模型中的相关集合属性。 / p>

答案 2 :(得分:0)

如果我理解正确,你想动态地将组合框添加到你的字符串中。

CS:

public class CollectionWrapper<T>  
{
    private string _title;
    public string Title
    {
        get { return _title; }
        set { _title = value; }
    }

    private IList<T> _collection;

    public IList<T> Collection
    {
        get { return _collection; }
        set { _collection = value; }
    }     

    public string DisplayMemeberPath
    {
       get;set;
    } 


}


public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public List<string> GetNewList()
    {
        return new List<string>
        {
           "1","2","3","4","1","2","3","4","1","2","3","4","1","2","3","4"
        };
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Items.Add(new CollectionWrapper<string> { Collection = GetNewList(), Title = (Items.Count + 1 ).ToString() , DisplayMemeberPath="Content"}); 
    }

    private ObservableCollection<CollectionWrapper<string>> _items;
    public ObservableCollection<CollectionWrapper<string>> Items
    {
        get
        {
            if (_items == null)
                _items = new ObservableCollection<CollectionWrapper<string>>();
            return _items;
        }
    }
}

XAML:

 <Window.Resources>
    <DataTemplate  x:Key="listItemTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <Label Content="{Binding Title}"/>
            <ComboBox Grid.Column="1" ItemsSource="{Binding Collection}" DisplayMemberPath="{Binding DisplayMemeberPath}"/>

        </Grid>            
    </DataTemplate>

</Window.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
    </Grid.RowDefinitions>


    <Button Content="Add List" Click="Button_Click"/>

    <ScrollViewer Grid.Row="1">
        <ItemsControl ItemTemplate="{StaticResource listItemTemplate}" ItemsSource="{Binding Items}"/>
    </ScrollViewer>
</Grid>

答案 3 :(得分:0)

实现这一目标的一种方法是,如果你有一个db记录的模型和一个记录列表的模型,即

为方便起见,我将使用Year示例。

class YearModel : INotifyPropertyChanged
{
    #region Members

    myService.Year _year;

    #endregion

    #region Properties

    public myService.Year Year
    {
        get { return _year; }
    }

    public Int32 id
    {
        get { return Year.id; }
        set
        {
            Year.id = value;
            NotifyPropertyChanged("id");
        }
    }

    public String Code
    {
        get { return Year.Code; }
        set
        {
            Year.Code = value;
            NotifyPropertyChanged("Code");
        }
    }

#region Construction

    public YearModel()
    {
        this._year = new SchoolMonitor_Service.Year
        {
            id = 0,
            Code = "",
        };
    }

    #endregion
}

然后是列表

class YearListModel
{
    myService.myServcieClient service = new myService.myServcieClient();

    #region Members

    private ObservableCollection<YearModel> _years;

    #endregion

    #region Properties

    public ObservableCollection<YearModel> Years
    {
        get { return _years; }
    }

    #endregion

    #region Construction

    public YearListModel()
    {
        _years = new ObservableCollection<YearModel>();

        foreach (SchoolMonitor_Service.Year y in service.GetYearList())
        {
            _years.Add(new YearModel
            {
                id = y.id,
                Code = y.Code
            }
                            );
        }
    }

    #endregion
}

然后创建一个ViewModel,获取您需要的所有列表我添加了YearGroups作为示例:

class YearFormViewModel
{
    public YearListModel YearList { get; set; }
    public YearGroupListModel YearGroupList { get; set; }

    public YearFormViewModel()
    {
        YearList = new YearListModel;
        YearGroupList = new YearGroupListModel();
    }
}

然后,您可以在窗口/页面中获取ViewModel:

xmlns:local="clr-namespace:myProject.Models"


<Page.Resources>
    <local:YearFormViewModel x:Key="myViewModel" />
</Page.Resources>

然后相应地绑定:

<ComboBox x:Name="cbYears" 
                      DataContext="{StaticResource ResourceKey=myViewModel}"
                      ItemsSource="{Binding Path=YearList.Years}"
                      SelectedValuePath="id" 
                      DisplayMemberPath="Code"/>
<ComboBox x:Name="cbYearGroups" 
                      DataContext="{StaticResource ResourceKey=myViewModel}"
                      ItemsSource="{Binding Path=YearGroupList.YearGroups}"
                      SelectedValuePath="id" 
                      DisplayMemberPath="Code"/>