SO社区,请耐心等待我,因为我是新手,我还在学习(慢慢地)。我试图在网上完全实现所有可能的解决方案但没有成功。我想我完全把自己与DependencyMethods,DependencyProperties,RelayCommands,ICommand,BaseViewModels等混淆了........
这是我的场景......我有一个MainWindow(MainWindow),其中一个Frame包含一个UserControl(SampleUC)。 MainWindow和UserControl DataContexts指向它们各自的ViewModel(MainWindowVM,SampleUCVM)。 MainWindowVM和SampleUCVM是Base ViewModel(BASEVM)的子代,它通过ObservableCollection帮助器类使用INotifyPropertyChanged。 SampleUC中有一个Combobox,它使用方法“fillFacility”保存在SampleUCVM中构造的Facilities ObservableCollection,并在Combobox中使用“GetFacilityNum()”方法选择时存储SelectedFacilityNum。
我想从SampleUCVM中提取“fillFacility”和“GetFacilityNum”方法,并将它们放在BASEVM或单独的类中,以便其他ViewModel可以访问和使用它们。它们将在我的整个项目中反复使用。有人能够向我解释如何做到这一点?感谢您的帮助和耐心!
SampleUC.xaml
<Grid>
<Label Content="Facility" HorizontalAlignment="Left" Margin="10,32,0,0" VerticalAlignment="Top" Width="87" Height="27"/>
<ComboBox Name="cboFacilities"
HorizontalAlignment="Left" Margin="119,37,0,0" VerticalAlignment="Top" Width="120"
DisplayMemberPath="FacilityName"
SelectedValuePath="FacilityName"
ItemsSource="{Binding Facilities}"
SelectedValue="{Binding SelectedFacility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
</Grid>
SampleUCVM
public class SampleUCVM : BASEVM
{
#region MySQL Connection
const string dbConnectionString = @"datasource=localhost;port=3306;Initial Catalog='optest1a1';username=root;password=";
#endregion
private ObservableCollection<Facilities> _facilitiesList;
private string _selectedFacility;
private int _selectedFacilityNum;
public ObservableCollection<Facilities> Facilities
{
get { return _facilitiesList; }
set
{
SetProperty(ref _facilitiesList, value, () => Facilities);
}
}
public string SelectedFacility
{
get { return _selectedFacility; }
set
{
SetProperty(ref _selectedFacility, value, () => SelectedFacility);
if (_selectedFacility != null)
{
GetFacilityNum();
}
}
}
public int SelectedFacilityNum
{
get { return _selectedFacilityNum; }
set { SetProperty(ref _selectedFacilityNum, value, () => SelectedFacilityNum); }
}
public SampleUCVM()
{
Facilities = new ObservableCollection<Facilities>();
fillFacilities();
}
private void fillFacilities()
{
using (MySqlConnection con = new MySqlConnection(dbConnectionString))
{
Facilities = new ObservableCollection<Facilities>();
con.Open();
string Query = "SELECT * FROM facilities";
MySqlCommand createCommand = new MySqlCommand(Query, con);
MySqlDataReader dr = createCommand.ExecuteReader();
int count = 1;
while (dr.Read())
{
string FacilityName = dr.GetString(1);
Facilities facilityname = new Facilities(count, FacilityName);
Facilities.Add(facilityname);
count++;
}
con.Close();
}
}
private void GetFacilityNum()
{
if (SelectedFacility != null)
{
using (MySqlConnection con = new MySqlConnection(dbConnectionString))
{
con.Open();
string Query = "SELECT Facility_ID_Num FROM facilities WHERE Facility_Name='" + SelectedFacility + "' ";
MySqlCommand createCommand = new MySqlCommand(Query, con);
MySqlDataReader dr = createCommand.ExecuteReader();
int count = 1;
while (dr.Read())
{
int FacilityNum = dr.GetInt32(0);
SelectedFacilityNum = FacilityNum;
count++;
}
con.Close();
}
}
}
}
BASEVM
public class BASEVM : ObservableObject
{
public BASEVM()
{
}
}
答案 0 :(得分:0)
你做的事情比实际情况复杂得多。
ObservableCollection<T>
足以通知WPF控件到目前为止发生的变化;只需确保它与XAML绑定正确。
就这样
public ObservableCollection<Facilities> Facilities
{
get { return _facilitiesList; }
set
{
SetProperty(ref _facilitiesList, value, () => Facilities);
}
}
是多余的,应该简化为
public ObservableCollection<Facilities> Facilities
{
get;
}
并且只从构造函数初始化一次。
只要您希望它在基本视图模型中,只需将代码移动到那里即可。然后从您的基础模型继承您的子模型,因此孩子将获得这样的属性作为他们自己的一部分。
忘记SetValue(...)
,除非您注册了自己的自定义DependencyProperty
,这仅适用于高级方案。
这些是起点。
玩得开心。
答案 1 :(得分:0)
我同意Peter Duniho
你的问题太宽泛,而且没有明确的答案,但我想向你强调一些观点。
您BASEVM
的目的是什么?为什么它继承自ObservableObject
包装对象的类,以便其他类可以通知 改变事件。 通常,此类设置为依赖项属性 在DependencyObjects上,并允许其他类观察任何更改 中的值。
如果您想要基本的通知更改功能,您可以执行以下操作。
public class ViewModelBase:INotifyPropertyChanged{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(this, args);
}
protected void RaisePropertyChanged([CallerMemberName]string propertyName = null)
{
OnPropertyChanged(propertyName);
}
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
RaisePropertyChanged(propertyName);
return true;
}
}
source
之后,您继承此ViewModelBase
类。当任何属性发生变化时,您可以像这样触发PropertyChanged
事件:
public int SelectedFacilityNum
{
get { return _selectedFacilityNum; }
set { SetProperty(ref _selectedFacilityNum,value); }
}
我想提出方法&#34; fillFacility&#34;和 &#34; GetFacilityNum&#34;从SampleUCVM中将它们放入 BASEVM或可以访问和使用它们的单独类 其他ViewModels
fillFacility
方法,如您的代码所示,正在处理database
。据我所知,在MVVM
模式中,ViewModels
旨在冥想View
和Model
视图模型充当视图和模型之间的中介, 并负责处理视图逻辑。通常,视图 model通过调用模型中的方法与模型交互 类。然后,视图模型以表单形式提供模型中的数据 该视图可以轻松使用。视图模型从中检索数据 模型,然后使数据可用于视图,并可能重新格式化 以某种方式使数据更容易处理视图。
因此,我建议将Data Access
逻辑从您的视图模型中分离到单独的Data Access
图层。例如,您可以使用Repository
模式并创建FacilityRepository
。然后,您可以将此存储库提供给ViewModels
需要此功能。如果你想要更严格,可以创建IFacilityRepository
接口,让FacilityRepository
实现它,然后将此接口注入任何需要此功能的ViewModel
。
答案 2 :(得分:0)
我会考虑为这种事情实现数据访问层。例如:
public class DataAccess
{
public ObservableCollection<Facilities> GetFacilities()
{
ObservableCollection<Facilities> facilities = new ObservableCollection<Facilities>();
using (MySqlConnection con = new MySqlConnection(dbConnectionString))
{
con.Open();
string Query = "SELECT * FROM facilities";
MySqlCommand createCommand = new MySqlCommand(Query, con);
MySqlDataReader dr = createCommand.ExecuteReader();
int count = 1;
while (dr.Read())
{
string FacilityName = dr.GetString(1);
facilities facilityname = new Facilities(count, FacilityName);
facilities.Add(facilityname);
count++;
}
con.Close();
}
return facilities;
}
}
然后,您可以在ViewModel类(或某些ViewModel基类)上包含此实例。
关于您的GetFacilityNum()
方法,这也可以进入DataAccess
课程,但我个人认为更好的解决方案是将Facility_ID_Num
作为您{的属性{1}}课程,如果可能的话。然后,您只需要修改Facilities
方法以将其拉入,但随后在应用程序中,您始终可以在没有任何数据库调用的情况下访问它,因为它将成为您{{1}的一部分模特。