[英]How to set DataContext of UserControl in C# MVVM
我是 MVVM 的新手,所以请和我一起裸露。
当前问题:我有一个 MainWindow,里面有一个 ServerView UserControl。 我将 UserControl 的 DataContext 绑定到 ServerViewModel。 但是,当单击“启动服务器”按钮和“停止服务器”按钮时,它不会触发 ServerViewModel 中的逻辑(OnStartServer 和 OnStopServer 方法)。 我哪里出错了?
主窗口.xaml
<Window x:Class="ServerGUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:ServerGUI.Views"
xmlns:vm="clr-namespace:ServerGUI.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type vm:ServerViewModel}">
<views:ServerView />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<views:ServerView Grid.Column="0" x:Name="ServerView" DataContext="{Binding ServerViewModel}" />
<Label Grid.Column="1" Content="Test" />
</Grid>
</Window>
主窗口.xaml.cs
using ServerGUI.ViewModels;
using System.Windows;
namespace ServerGUI
{
public partial class MainWindow : Window
{
public MainViewModel MainViewModel { get; set; }
public MainWindow()
{
MainViewModel = new MainViewModel();
DataContext = MainViewModel;
InitializeComponent();
}
}
}
主视图模型.cs
namespace ServerGUI.ViewModels
{
public class MainViewModel : BaseViewModel
{
public ServerViewModel ServerViewModel { get; set; } = new ServerViewModel();
public MainViewModel()
{
}
}
}
服务器视图.xaml
<UserControl x:Class="ServerGUI.Views.ServerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:data="clr-namespace:ServerGUI.Models"
xmlns:vms="clr-namespace:ServerGUI.ViewModels"
d:DataContext="{d:DesignInstance Type=vms:ServerViewModel}"
mc:Ignorable="d"
d:DesignHeight="110" d:DesignWidth="200" Background="White">
<GroupBox DataContext="{Binding ServerViewModel}" Grid.Column="0" Header="Server Properties">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Start Server" Command="{Binding Path=StartServerCommand}" Margin="3 5 3 0" />
<Button Grid.Row="1" Content="Stop Server" Command="{Binding Path=StopServerCommand}" Margin="3 5 3 0" />
<Label Grid.Row="2" x:Name="lblServerStatus" Content="Server Status: Offline" />
</Grid>
</GroupBox>
</UserControl>
服务器视图.xaml.cs
using System.Windows.Controls;
namespace ServerGUI.Views
{
public partial class ServerView : UserControl
{
public ServerView()
{
InitializeComponent();
}
}
}
服务器视图模型.cs
using ServerGUI.Commands;
using ServerGUI.Models;
using System.Windows.Input;
namespace ServerGUI.ViewModels
{
public class ServerViewModel : BaseViewModel
{
#region Fields and Properties
private readonly ServerModel _serverModel;
public bool IsRunning
{
get => _serverModel.IsRunning;
}
#endregion
#region ICommands
private readonly RelayCommand _startServerCommand;
private readonly RelayCommand _stopServerCommand;
public ICommand StartServerCommand => _startServerCommand;
public ICommand StopServerCommand => _stopServerCommand;
#endregion
#region Constructor
public ServerViewModel()
{
_serverModel = new ServerModel();
_startServerCommand = new RelayCommand(OnStartServer, CanStartServer);
_stopServerCommand = new RelayCommand(OnStopServer, CanStopServer);
}
#endregion
#region Methods
private void OnStartServer(object command)
{
_serverModel.IsRunning = true;
_startServerCommand.InvokeCanExecuteChanged();
_stopServerCommand.InvokeCanExecuteChanged();
}
private void OnStopServer(object command)
{
_serverModel.IsRunning = false;
_startServerCommand.InvokeCanExecuteChanged();
_stopServerCommand.InvokeCanExecuteChanged();
}
private bool CanStartServer(object command) => !IsRunning;
private bool CanStopServer(object command) => IsRunning;
#endregion
}
}
基础视图模型.cs
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace ServerGUI.ViewModels
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
return false;
}
}
}
中继命令.cs
using System;
using System.Windows.Input;
namespace ServerGUI.Commands
{
class RelayCommand : ICommand
{
private readonly Action<object> _executeAction;
private readonly Func<object, bool> _canExecuteAction;
public event EventHandler CanExecuteChanged;
public RelayCommand(Action<object> executeAction, Func<object, bool> canExecuteAction)
{
_executeAction = executeAction;
_canExecuteAction = canExecuteAction;
}
public void Execute(object parameter) => _executeAction(parameter);
public bool CanExecute(object parameter) => _canExecuteAction?.Invoke(parameter) ?? true;
public void InvokeCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
服务器模型.cs
using System.ComponentModel;
namespace ServerGUI.Models
{
public class ServerModel : INotifyPropertyChanged
{
private bool isRunning = default;
public event PropertyChangedEventHandler PropertyChanged;
public ServerModel()
{
IsRunning = false;
}
public bool IsRunning
{
get => isRunning;
set
{
isRunning = value;
RaisePropertyChanged(nameof(IsRunning));
}
}
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在ServerView.xaml
你的UserControl
假设它的DataContext
是类型ServerViewModel
,然后在你的GroupBox
你要求它的属性ServerViewModel
,所以它变得像ServerViewModel.ServerViewModel
一样为空。
删除GroupBox
DataContext
分配
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.