WPF多个ViewModels和多个UserCotnrols

时间:2015-08-24 20:32:44

标签: c# wpf mvvm data-binding

所以我有一个包含TabControl的页面,它使用多个UserControls(每个用户控件代表一个TabItem的内容)。

我在两个共享相同ItemsSource(OrganizationSource)和SelectedValue(OrganizationSelected)属性的用户控件中都有一个ComboBox,

但是我似乎无法绑定到EventDetails UserControl中的ComboBox,但它在OrganizationDetails UserControl中完美无缺地工作。

OutreachMVVM设置为选项卡所在父页面的DataContext。我仍然需要为用户控件本身设置datacontexts才能使其正常工作。

我只需要弄清楚如何在EventDetails内设置ComboBox的绑定。我看到了一些关于依赖属性的东西,但我不明白。我以为我能够将EventDetails内的ComboBox的绑定设置为OrganizationDetails内的ComboBox的绑定,但事实并非如此。

internal class OutreachMVVM : ViewModelBase
{
    public OutreachMVVM()
    {

        EventDetails = new EventDetailsVMB();   
        OrganizationDetails = new OrganizationDetailsVMB();
    }

    public EventDetailsVMB EventDetails { get; set; }
    public OrganizationDetailsVMB OrganizationDetails { get; set; }
}

EventDetailsVMB:

class EventDetailsVMB : ViewModelBase
{
    private string _eventTypeSelected;
    private string _zipSelected;

    private readonly UserListTableAdapter _userListTableAdapter = new UserListTableAdapter();
    private readonly EventTypeListTableAdapter _eventTypeListTableAdapter = new EventTypeListTableAdapter();
    private readonly CityListTableAdapter _cityListTableAdapter = new CityListTableAdapter();
    private readonly LocationInfoByZipTableAdapter _locationInfoByZipTableAdapter = new LocationInfoByZipTableAdapter();

    public string User { get; set; }
    public string EventName { get; set; }
    public string Location { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string County { get; set; }
    public string ServiceArea { get; set; }

    //Set EventType CombBox
    public ObservableCollection<string> EventTypeSource
    {
        get
        {
            var eventTypeList = _eventTypeListTableAdapter.GetEventTypeList();
            var eventTypeSource = new ObservableCollection<string>();
            eventTypeSource.AddRange(from DataRow row in eventTypeList.Rows select row.ItemArray[0].ToString());
            return eventTypeSource;
        }
    }

    //Set User ComboBox
    public ObservableCollection<string> UserSource
    {
        get
        {
            var userList = _userListTableAdapter.GetUserList();
            var userSource = new ObservableCollection<string>();

            foreach (var username in Enumerable.Where(userList, username => username.Username == Environment.UserName))
            {

                User = username.FullName;
            }

            userSource.AddRange(from DataRow row in userList.Rows select row.ItemArray[0].ToString());
            OnPropertyChanged("User");
            return userSource;
        }
    }

    //Set City RadAutoCompleteBox
    public ObservableCollection<string> CitySource
    {
        get
        {
            var cityList = _cityListTableAdapter.GetCityList();
            var citySource = new ObservableCollection<string>();
            citySource.AddRange(from DataRow row in cityList.Rows select row.ItemArray[0].ToString());
            return citySource;
        }
    } 


    public string EventTypeSelected
    {
        get { return _eventTypeSelected; }
        set
        {
            _eventTypeSelected = value;
            OnPropertyChanged("EventTypeSelected");
        }
    }

    public string ZipSelected 
    { 
        get { return _zipSelected;  }
        set
        {
            _zipSelected = value;
            var locationInfo = _locationInfoByZipTableAdapter.GetLocationInfoByZip(_zipSelected);
            if (locationInfo.Rows.Count != 0)
            {
                City = locationInfo.Rows[0].ItemArray[0].ToString();
                State = locationInfo.Rows[0].ItemArray[1].ToString();
                County = locationInfo.Rows[0].ItemArray[2].ToString();
                ServiceArea = locationInfo.Rows[0].ItemArray[3].ToString();
            }
            else if (ZipSelected.Length == 5) {}
            else
            {
                City = "";
                State = "TX";
                County = null;
                ServiceArea = null;
            }
            OnPropertyChanged("City");
            OnPropertyChanged("State");
            OnPropertyChanged("County");
            OnPropertyChanged("ServiceArea");
        } 
    }
}

OrganizationDetailsVMB:

class OrganizationDetailsVMB : ViewModelBase
{

    private string _organizationName;
    private string _street1;
    private string _street2;
    private string _city;
    private string _state;
    private string _zip;
    private string _county;
    private string _serviceArea;

    private bool _cbo;
    private bool _fbo;
    private bool _mo;
    private bool _sbo;
    private bool _sno;

    private readonly OrganizationListTableAdapter _organizationListTableAdapter = new OrganizationListTableAdapter();
    private readonly OrgByNameTableAdapter _orgByNameTableAdapter = new OrgByNameTableAdapter();
    private readonly OrgTypeByOrgNameTableAdapter _orgTypeByOrgNameTableAdapter = new OrgTypeByOrgNameTableAdapter();

    public string OrganizationSelected
    {
        get { return _organizationName; }
        set
        {
            _organizationName = value;
            var organizationQueryResults = _orgByNameTableAdapter.GetOrganizationByName(_organizationName);
            var orgTypeQueryResults = _orgTypeByOrgNameTableAdapter.GetOrgTypeByName(_organizationName);
            if (organizationQueryResults.Rows.Count != 0)
            {
                OrgStreet1Value = organizationQueryResults.Rows[0].ItemArray[1].ToString();
                OrgStreet2Value = organizationQueryResults.Rows[0].ItemArray[2].ToString();
                OrgCityValue = organizationQueryResults.Rows[0].ItemArray[3].ToString();
                OrgStateValue = organizationQueryResults.Rows[0].ItemArray[4].ToString();
                OrgZipValue = organizationQueryResults.Rows[0].ItemArray[5].ToString();
                OrgCountyValue = organizationQueryResults.Rows[0].ItemArray[6].ToString();
                OrgServiceAreaValue = organizationQueryResults.Rows[0].ItemArray[7].ToString();
                CBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[1]);
                FBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[2]);
                SBO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[3]);
                MO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[4]);
                SNO = Convert.ToBoolean(orgTypeQueryResults.Rows[0].ItemArray[5]);
            }
            else
            {
                OrgStreet1Value = "";
                OrgStreet2Value = "";
                OrgCityValue = "";
                OrgStateValue = "";
                OrgZipValue = "";
                OrgCountyValue = "";
                OrgServiceAreaValue = "";
                CBO = false;
                FBO = false;
                SBO = false;
                MO = false;
                SNO = false;
            }
        }
    }

    public ObservableCollection<string> OrganizationSource
    {
        get
        {
            var organizationList = _organizationListTableAdapter.GetOrganizationList();
            var organizationSource = new ObservableCollection<string>();
            organizationSource.AddRange(from DataRow row in organizationList.Rows select row.ItemArray[0].ToString());
            return organizationSource;
        }
    }

    public string OrgStreet1Value
    {
        get { return _street1; }
        set
        {
            if (_street1 != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgStreet1Value" });
                _street1 = value;
                OnPropertyChanged("OrgStreet1Value");
            }
        }
    }

    public string OrgStreet2Value
    {
        get { return _street2; }
        set
        {
            if (_street2 != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgStreet2Value" });
                _street2 = value;
                OnPropertyChanged("OrgStreet2Value");
            }
        }
    }

    public string OrgCityValue
    {
        get { return _city; }
        set
        {
            if (_street1 != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgCityValue" });
                _city = value;
                OnPropertyChanged("OrgCityValue");
            }
        }
    }

    public string OrgStateValue
    {
        get { return _state; }
        set
        {
            if (_state != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgStateValue" });
                _state = value;
                OnPropertyChanged("OrgStateValue");
            }
        }
    }

    public string OrgZipValue
    {
        get { return _zip; }
        set
        {
            if (_zip != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgZipValue" });
                _zip = value;
                OnPropertyChanged("OrgZipValue");
            }
        }
    }

    public string OrgCountyValue
    {
        get { return _county; }
        set
        {
            if (_county != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgCountyValue" });
                _county = value;
                OnPropertyChanged("OrgCountyValue");
            }
        }
    }

    public string OrgServiceAreaValue
    {
        get { return _serviceArea; }
        set
        {
            if (_serviceArea != value)
            {
                Validator.ValidateProperty(value,
                    new ValidationContext(this, null, null) { MemberName = "OrgServiceAreaValue" });
                _serviceArea = value;
                OnPropertyChanged("OrgServiceAreaValue");
            }
        }
    }

    public bool CBO
    {
        get { return _cbo; }
        set
        {
            _cbo = value;
            OnPropertyChanged("CBO");
        }
    }

    public bool FBO
    {
        get { return _fbo; }
        set
        {
            _fbo = value;
            OnPropertyChanged("FBO");
        }
    }

    public bool SBO
    {
        get { return _sbo; }
        set
        {
            _sbo = value;
            OnPropertyChanged("SBO");
        }
    }

    public bool MO
    {
        get { return _mo; }
        set
        {
            _mo = value;
            OnPropertyChanged("MO");
        }
    }

    public bool SNO
    {
        get { return _sno; }
        set
        {
            _sno = value;
            OnPropertyChanged("SNO");
        }
    }
}

EventDetailsTab:

<TabItem Header="Event Details" x:Name="EventDetailsTab"
            Style="{StaticResource TabStyle}"
            DataContext="{Binding EventDetails}">
    <eventTabs:_1_EventDetailsTab />
</TabItem>

OrganizationDetailsTab:

<TabItem Header="Organization" x:Name="OrganizationTab"
            Style="{StaticResource TabStyle}"
            DataContext="{Binding OrganizationDetails}">
    <eventTabs:_2_OrganizationTab />
</TabItem>

正如我所说,绑定整体上完美无缺,但是我想引用与OrganizationDetails相关联的绑定,以获取驻留在EventDetailsTab和OrganizationDetailsTab中的控件。

该项目的代码如下......

<ComboBox Name="OrgNameComboBox" ItemsSource="{Binding OrganizationSource}"
                SelectedValue="{Binding OrganizationSelected,
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}" />

3 个答案:

答案 0 :(得分:1)

您要将事件详细信息选项卡的DataContext设置为{Binding EventDetails},将组织选项卡的DataContext设置为{Binding OrganizationDetails},但将OrganizationSourceOrganizationSelected字段设置为<ComboBox Name="OrgNameComboBox" ItemsSource="{Binding OrganizationSource}" DataContext="{Binding RelativeSource={RelativeSource AncestorType=TabControl}, Path=DataContext.OrganizationDetails}" SelectedValue="{Binding OrganizationSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> ComboBox绑定仅存在于OrganizationDetailsVMB类中。快速入侵是将您的事件详细信息更改为ComboBox以指向正确的位置,其中RelativeSource绑定回TabItem的DataContext,然后再次返回到OrganizationDetails:

Users = Array ( [0] => 1 [1] => 1 [2] => 1 )
Types = Array ( [0] => 0 [1] => 1 [2] => 0 )

虽然我认为你需要清理你的架构,但要说实话。您的视图模型与您的基础数据模型非常紧密地耦合,而不是视图,甚至是您在getter中访问表适配器的位置,这意味着A)您无法进行会话管理,B)您的视图性能现在将被你的DAL限制,你将开始遇到性能问题,而C)试图引入任何类型的多线程将导致你的ORM中出现各种访问冲突。

答案 1 :(得分:0)

A)

如果您希望在AppMulti Window中包含一些数据(例如组合框信息),这种方式很好:

创建3 ViewModel(全部继承自INotifyPropertyChanged)。

  1. OrganizationViewModel 包含 OrganizationSource OrganizationSelected < / LI>
  2. OrganizationDetailsViewModel WHITHOUT OrganizationSource OrganizationSelected < / LI>
  3. OrganizationEventsViewModel WHITHOUT OrganizationSource OrganizationSelected < / LI>

    现在,您可以创建一个名为Static&amp;的简单GeneralData类。在static类型中创建一个OrganizationViewModel属性,如下所示:

    public static class GeneralData{
       public static OrganizationViewModel Organization {get;set;}
    }
    

    App.xaml.cs中填充Organization类的GeneralData属性,其中包含OrganizationViewModel的新实例。

    好的......现在我们有了开始玩的所有东西......

    每次要填充ComboBox时,都应该使用Organization类的GeneralData [静态属性],如下所示:

    <ComboBox Name="OrgNameComboBox"
              DataSource="{Binding Source={x:Static GeneralData.Organization}}"
              ItemsSource="{Binding Source={x:Static GeneralData.Organization.OrganizationSource}}"
              SelectedValue="{Binding Source={x:Static GeneralData.Organization.OrganizationSelected,
                                      Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    

    每次你想检查在代码隐藏中选择哪个Combobox项目(例如在ViewModels内),你可以像这样轻松检查:

    var selectedOrganisation = GeneralData.Organization.OrganizationSelected;
    

    注意:在关闭包含ComboBox的窗口之前,我建议您运行此代码(以确保没有对static属性的任何活动引用):

    BindingOperations.ClearAllBindings(OrgNameComboBox);
    

    B)

    如果您只有1个窗口包含2个UserControl,则阻止static属性,而不是以上方式使用此方式:

    创建3 ViewModel(全部继承自INotifyPropertyChanged)。

    1. OrganizationViewModel 包含 OrganizationSource OrganizationSelected < / LI>
    2. OrganizationDetailsViewModel WHITHOUT OrganizationSource OrganizationSelected < / LI>
    3. OrganizationEventsViewModel WHITHOUT OrganizationSource OrganizationSelected < / LI>

      现在可以轻松实现此方案:

      Window1.xaml.cs

      Window1.DataSource= new OrganizationViewModel();
      

      EventUserControl.xaml.cs

      EventUserControl.DataSource= new OrganizationEventsViewModel();
      

      OrganizationDetailsUserControl.xaml.cs

      EventUserControl.DataSource= new OrganizationDetailsViewModel();
      

      现在在DependencyPropertyEventUserControl中创建OrganizationDetailsUserControl,为其提供SelectedItem ComboBox。您的房产类型应为string。您可以在this tutorial上创建DependencyProperty个基础。 例如,在DependencyProperty的{​​{1}}中UserControl使用此名称: SelectedOrganisation

      好的,将Combobox放入Window1.xaml(不在任何UserControl内)。 现在,我们从SelectedOrganisation外部填充这些UserControls,如下面的代码。

      Window1.xaml

      <uc.OrganizationDetailsUserControl 
          SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
      
      <uc.EventUserControl
          SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
      

      现在,您SelectedItem内的ComboBox UserControl可以在UserControls内使用ViewModels,并调用SelectedOrganisation的某些方法guard-minitest作为方法参数。

答案 2 :(得分:0)

我采取的路线是MVVM Light Toolkit