[英]How to set DataContext of UserControl in C# MVVM
I am new to MVVM so please bare with me.我是 MVVM 的新手,所以请和我一起裸露。
Current issue: I have a MainWindow with a ServerView UserControl inside.当前问题:我有一个 MainWindow,里面有一个 ServerView UserControl。 I bind the DataContext of the UserControl to the ServerViewModel.
我将 UserControl 的 DataContext 绑定到 ServerViewModel。 However when clicking the "Start Server"-button and "Stop Server"-button it will not trigger the logic in the ServerViewModel (the OnStartServer and OnStopServer methods).
但是,当单击“启动服务器”按钮和“停止服务器”按钮时,它不会触发 ServerViewModel 中的逻辑(OnStartServer 和 OnStopServer 方法)。 Where do I go wrong?
我哪里出错了?
MainWindow.xaml主窗口.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>
MainWindow.xaml.cs主窗口.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();
}
}
}
MainViewModel.cs主视图模型.cs
namespace ServerGUI.ViewModels
{
public class MainViewModel : BaseViewModel
{
public ServerViewModel ServerViewModel { get; set; } = new ServerViewModel();
public MainViewModel()
{
}
}
}
ServerView.xaml服务器视图.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>
ServerView.xaml.cs服务器视图.xaml.cs
using System.Windows.Controls;
namespace ServerGUI.Views
{
public partial class ServerView : UserControl
{
public ServerView()
{
InitializeComponent();
}
}
}
ServerViewModel.cs服务器视图模型.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
}
}
BaseViewModel.cs基础视图模型.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;
}
}
}
RelayCommand.cs中继命令.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);
}
}
ServerModel.cs服务器模型.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));
}
}
}
In ServerView.xaml
your UserControl
assumes that its DataContext
is of type ServerViewModel
, and then in your GroupBox
you ask for property ServerViewModel
of it, so it becomes smth like ServerViewModel.ServerViewModel
which is null.在
ServerView.xaml
你的UserControl
假设它的DataContext
是类型ServerViewModel
,然后在你的GroupBox
你要求它的属性ServerViewModel
,所以它变得像ServerViewModel.ServerViewModel
一样为空。
Remove DataContext
assignment in GroupBox
删除
GroupBox
DataContext
分配
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.