WPF MVVM按钮从视图控制界面



我对WPF和MVVM概念很陌生,我试图解决可能愚蠢的问题。我有MainViewModel,我控制什么应该在屏幕上看到根据按下的按钮在菜单。

class MainViewModel : ObservableObject
{
public RelayCommand HomeViewCommand { get; set; }       
public RelayCommand SettingsViewCommand { get; set; }
public HomeViewModel HomeVM { get; set; }      
public SettingsViewModel SettingsVM { get; set; }
private object _currentView;
public object CurrentView
{
get { return _currentView; }
set 
{ 
_currentView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
HomeVM = new HomeViewModel();            
SettingsVM = new SettingsViewModel();
CurrentView = HomeVM;
HomeViewCommand = new RelayCommand(o =>
{
CurrentView = HomeVM;
});          
SettingsViewCommand = new RelayCommand(o =>
{
CurrentView = SettingsVM;
});
}

我的一个视图是SettingsView。在这个视图中,我有一个按钮,它应该检查连接字符串是否正确。因为我要用到很多SQL命令我的想法是,把所有关于SQL的代码放到一个文件夹里。所以基本上项目是MVVM(file)>View(file),ViewModel(file)....和SQL(文件)在…可悲的是,当我添加到setingsview sql时,应用程序因为'对象引用未设置为对象的实例'而下降

在setingsview中是:

public partial class SettingsView : UserControl
{
private readonly HSQLTestConnection _SQLTestConnection;         
public SettingsView(HSQLTestConnection SQLTestConnection)
{
InitializeComponent();
_SQLTestConnection = SQLTestConnection;

按钮是这样的:_SQLTestConnection.TryConnectionString(ConnectionString);

模型为空:

class SettingsViewModel
{
public SettingsViewModel()
{
}
}

SQL的接口是:

public interface HSQLTestConnection
{       
void TryConnectionString(string ConnectionString);
}

和SQL函数:

public class SQLTestConnection : HSQLTestConnection
{       
public void TryConnectionString(string ConnectionString)
{           
//do something
}
}

应用程序不显示任何错误,正在工作和改变视图很好,我认为问题是与公共SettingsView(HSQLTestConnection SQLTestConnection)但我找不到解决这个问题的方法。因为我将有多个SQL类,所以我想用这种方式解决它。它曾经在我编写的不同应用程序中工作,但我没有使用RellayCommand,我想尝试一下。提前感谢您的帮助。

我看到SettingsView类扩展了UserControl类。这有问题,因为

  • 你说你想遵循MVVM设计模式,但你的用户控制代码(SettingsView)在构造函数中引用了你的数据库连接(HSQLTestConnection)。你不应该混合视图代码与数据库代码。
  • 你的SettingsView是由框架初始化的,所以它应该在构造函数中获得HSQLTestConnection参数的值?

在任何情况下,你的视图不应该有任何数据库逻辑,至少如果你想遵循MVVM。

您可以做的是在设置视图SettingsViewModel的视图模型中启动数据库连接。不是很好,但稍微好一点。

既然你提到会有"相当多的SQL命令",我建议你把这些代码分离成一个专用的服务,然后在你的视图模型中使用这个服务。

public interface IMyDatabaseService
{
bool TestConnection();
IEnumerable<SomeDataObject> GetData();
...
}

然后在需要的地方传递这个接口:

public class SettingsViewModel : INotifyPropertyChanged
{
private readonly IMyDatabaseService databaseService;
private bool connectionSuccessful;
public RelayCommand TestConnectionCommand { get; set; }
public bool ConnectionSuccessful 
{ 
get => connectionSuccessful; 
set 
{ 
connectionSuccessfull = value;
var propertyName = nameof(ConnectionSuccessful);
PropertyChanged?.Invoke(this, new (propertyName));
}
}
public SettingsViewModel(IMyDatabaseService databaseService)
{
this.databaseService = databaseService;
TestConnectionCommand = new RelayCommand(_ => 
ConnectionSuccessful = databaseService.TestConnection()
);
...
}
}
public class MainViewModel
{
...
public MainViewModel()
{
...
IMyDatabaseService databaseService = new MyDatabaseService();
SettingsVM = new SettingsViewModel(databaseService);
...
}
...
}

注意TestConnectionCommandConnectionSuccesful布尔值。

该命令将调用数据库服务,这是您将绑定按钮的对象。

类似地,可以在视图中绑定布尔值以显示连接状态。由于无论何时运行该命令,该值都可能发生变化,因此必须调用PropertyChanged来让框架知道该值发生了变化。在本例中,调用是在setter中完成的。

假设您的数据上下文设置正确,在您的SettingsView视图中,您现在将有:

...
<Button Command="{Binding TestConnectionCommand}"> Test </Button>

<TextBlock Text="Connection failed!">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ConnectionSuccessfull}" Value="True">
<Setter Property="Text" Value="Connection successful!" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
...

我使用了一个带有数据触发器的文本块来显示连接状态,但是您可以使用布尔值和数据触发器来做任何您想做的事情。也许显示一个模态对话框或其他东西。

更好的是使用某种依赖注入来注入你的数据库服务和其他依赖,同时使数据库代码异步,这样你的UI就不会冻结,但这将是未来你要弄清楚的。

最新更新