WPF 多个视图模型和多个用户 Cotnrols
本文关键字:用户 Cotnrols 视图 WPF 模型 | 更新日期: 2023-09-27 18:09:41
所以我有一个页面,其中包含一个使用多个用户控件的 TabTControl(每个用户控件表示 TabItem 的内容(。
我在共享相同 ItemsSource (OrganizationSource
( 和 SelectedValue( OrganizationSelected
( 属性的两个用户控件中都有一个组合框,
但是,我似乎无法绑定到EventDetails
用户控件中的ComboBox,但它在OrganizationDetails
用户控件中完美运行。
OutreachMVVM
设置为选项卡所在的父页面的数据上下文。我仍然必须为用户控件本身设置数据上下文才能正常工作。
我只需要弄清楚如何在EventDetails
内设置组合框的绑定。我看到了一些关于依赖属性的东西,但我不明白。我以为我可以将EventDetails
内部组合框的绑定设置为与OrganizationDetails
内部组合框的绑定相同,但事实并非如此。
internal class OutreachMVVM : ViewModelBase
{
public OutreachMVVM()
{
EventDetails = new EventDetailsVMB();
OrganizationDetails = new OrganizationDetailsVMB();
}
public EventDetailsVMB EventDetails { get; set; }
public OrganizationDetailsVMB OrganizationDetails { get; set; }
}
事件详情VMB:
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");
}
}
}
组织详细信息VMB:
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");
}
}
}
"事件详细信息"选项卡:
<TabItem Header="Event Details" x:Name="EventDetailsTab"
Style="{StaticResource TabStyle}"
DataContext="{Binding EventDetails}">
<eventTabs:_1_EventDetailsTab />
</TabItem>
"组织详细信息"选项卡:
<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}" />
您将事件详细信息选项卡的 DataContext 设置为 {Binding EventDetails}
,将组织的 DataContext 选项卡设置为 {Binding OrganizationDetails}
,但组合框绑定到的OrganizationSource
和OrganizationSelected
字段仅存在于 OrganizationDetailsVMB 类中。一个快速的技巧是更改您的事件详细信息 ComboBox 以指向正确的位置,并将 RelativeSource 绑定回 TabItem 的 DataContext,然后再次向下指向 OrganizationDetails:
<ComboBox Name="OrgNameComboBox" ItemsSource="{Binding OrganizationSource}"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=TabControl}, Path=DataContext.OrganizationDetails}"
SelectedValue="{Binding OrganizationSelected,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
老实说,尽管我认为您需要清理您的架构。您的视图模型看起来与基础数据模型而不是视图紧密耦合,以至于您甚至可以在 getter 中访问表适配器,这意味着 A( 您无法进行会话管理,B( 您的视图性能现在将受到 DAL 的限制,您将开始遇到性能问题, C(尝试引入任何类型的多线程将导致ORM中的各种访问冲突。
A(
当您想要跨App
或Multi Window
拥有一些数据(如组合框信息(时,这种方式很好:
创建 3 个ViewModel
(全部继承自 INotifyPropertyChanged
个(。
-
OrganizationViewModel
: 包括OrganizationSource
和OrganizationSelected
-
OrganizationDetailsViewModel
: 惠特OrganizationSource
和OrganizationSelected
-
OrganizationEventsViewModel
: 惠特豪特OrganizationSource
和OrganizationSelected
现在,您可以创建一个名为 GeneralData
的简单 Static
类,并在其中创建一个OrganizationViewModel
类型的 static
属性,如下所示:
public static class GeneralData{
public static OrganizationViewModel Organization {get;set;}
}
在App.xaml.cs
中,用 OrganizationViewModel
的新实例填充 GeneralData
类的 Organization
属性。
还行。。。现在我们有了开始玩所需的一切......
每次你想填充ComboBox
你应该使用GeneralData
类的Organization
[静态属性],如下所示:
<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}" />
每次您想检查在代码隐藏中选择了组合框的哪个项目时(例如在ViewModels
内(,您可以轻松地像这样检查它:
var selectedOrganisation = GeneralData.Organization.OrganizationSelected;
注意:我建议您在关闭包含ComboBox的窗口之前运行此代码(以确保没有任何对静态属性的活动引用(:
BindingOperations.ClearAllBindings(OrgNameComboBox);
二(
如果您只有 1 个窗口包含 2 个用户控件,则阻止static
属性,而不是上述方式使用以下方式:
创建 3 个ViewModel
(全部继承自 INotifyPropertyChanged
个(。
-
OrganizationViewModel
: 包括OrganizationSource
和OrganizationSelected
-
OrganizationDetailsViewModel
: 惠特豪特OrganizationSource
和OrganizationSelected
-
OrganizationEventsViewModel
: 惠特豪特OrganizationSource
和OrganizationSelected
现在轻松实现此方案:
在Window1.xaml.cs
:
Window1.DataSource= new OrganizationViewModel();
在EventUserControl.xaml.cs
:
EventUserControl.DataSource= new OrganizationEventsViewModel();
在OrganizationDetailsUserControl.xaml.cs
:
EventUserControl.DataSource= new OrganizationDetailsViewModel();
现在在EventUserControl
和OrganizationDetailsUserControl
中创建一个DependencyProperty
,以使它们具有ComboBox
SelectedItem
。您的住宿类型应为 string
。您可以根据本教程创建DependencyProperty
基础。例如,在两个UserControl
s: SelectedOrganisation
中都对DependencyProperty
使用此名称
好的,将Combobox
放在Window1.xaml
中(而不是在任何UserControl
内(。现在我们从外部填充这些SelectedOrganisation
,如以下代码UserControls
。
在Window1.xaml
<uc.OrganizationDetailsUserControl
SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
<uc.EventUserControl
SelectedOrganisation="{Binding ElementName=OrgNameComboBox, Path=SelectedItem}"/>
现在,您在UserControl
中拥有了ComboBox
的SelectedItem
,您可以在UserControls
中使用它,并使用SelectedOrganisation
作为方法参数调用ViewModels
的一些方法。
我走的路线是MVVM Light Toolkit。