繁体   English   中英

如何在 C# MVVM 中设置 UserControl 的 DataContext

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM