c# - 调用命令方法时属性为空

标签 c# .net wpf mvvm

调用 RefreshServices() 时,SelectedComputerSelectedCustomer 都为空,即使我实际选择它们时它们不是空的。

为什么?

/edit:忘记在 XAML 中发布按钮的声明。现在更新了。

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    MainViewModel _main = new MainViewModel();
    public MainWindow()
    {
        InitializeComponent();
        DataContext = _main;
    }
}

XAML:

<Window.Resources>
    <vm:MainViewModel x:Key="viewModel" />
</Window.Resources>
<Border Margin="10">
    <Grid>


        <!-- Comboboxes -->
        <GroupBox Header="Computer" Grid.Column="0" Grid.ColumnSpan="4" Margin="0 0 4 4">
            <ComboBox ItemsSource="{Binding ComputerNames}"
                      SelectedItem="{Binding SelectedComputer}"
                      IsSynchronizedWithCurrentItem="True"
                      SelectedIndex="0"/>
        </GroupBox>
        <GroupBox Header="Customer" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="0 0 4 4" >
            <ComboBox ItemsSource="{Binding CustomerNames}"
                      SelectedItem="{Binding SelectedCustomer}"
                      IsSynchronizedWithCurrentItem="True"
                      SelectedIndex="0"/>
        </GroupBox>

        <!-- Main list -->
        <DataGrid x:Name="dataGrid" Grid.Row="2" Grid.ColumnSpan="8"
                  ItemsSource="{Binding Path=Services, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                  AutoGenerateColumns="False"
                  IsReadOnly="True">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Width="*"  Binding="{Binding DisplayName}"/>
                <DataGridTextColumn Header="Status" Width="*" Binding="{Binding Status}" />
                <DataGridTextColumn Header="Machine Name" Width="*" Binding="{Binding MachineName}" />
            </DataGrid.Columns>
        </DataGrid>

        <!-- Buttons-->
        <Button Grid.Row="5" Grid.Column="0" Margin="0 4 4 4" Content="Start"
                Command="{Binding Path=StartServiceCommand, Source={StaticResource viewModel}}"
                CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
        <Button Grid.Row="5" Grid.Column="1" Margin="4 4 0 4" Content="Stop"
                Command="{Binding Path=StopServiceCommand, Source={StaticResource viewModel}}"
                CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
        <Button Grid.Row="5" Grid.Column="3" Margin="4 4 0 4" Content="Refresh"
                Command="{Binding Path=RefreshServicesCommand, Source={StaticResource viewModel}}" />


    </Grid>
</Border>

MainViewModel.cs 公共(public)类 MainViewModel :INotifyPropertyChanged { #region INotify 方法 公共(public)事件 PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    #endregion

    /*---------------------------- C U S T O M E R S -----------------------------*/

    #region Customer Properties

    private string _selectedCustomer;
    private ObservableCollection<string> _customerNames;

    public string SelectedCustomer
    {
        get => _selectedCustomer;
        set
        {
            SetField(ref _selectedCustomer, value);
            Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
        }
    }

    public ObservableCollection<string> CustomerNames
    {
        get => _customerNames;
        set
        {
            SetField(ref _customerNames, value);
            Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
        }
    }

    #endregion

    /*---------------------------- S E R V I C E S -----------------------------*/

    #region Services Properties
    private ObservableCollection<ServiceController> _services;
    private ObservableCollection<ServiceController> _selectedServices;

    public ObservableCollection<ServiceController> SelectedServices
    {
        get => _selectedServices;
        set => SetField(ref _selectedServices, value);
    }
    public ObservableCollection<ServiceController> Services
    {
        get => _services;
        set => SetField(ref _services, value);
    }

    #endregion

    /*---------------------------- C O M P U T E R S -----------------------------*/

    #region Computer Properties

    private string _selectedComputer;
    private ObservableCollection<string> _computerNames;


    public string SelectedComputer
    {
        get => _selectedComputer;
        set
        {
            SetField(ref _selectedComputer, value);
            CustomerNames = Utils.UpdatedCustomerNames(SelectedComputer);
        }
    }

    public ObservableCollection<string> ComputerNames
    {
        get => _computerNames;
        set => SetField(ref _computerNames, value);
    }

    #endregion

/*---------------------------- C O M M A N D S -----------------------------*/

    #region Commands

    public StartServiceCommand StartServiceCommand { get; set; }
    public void StartService(ObservableCollection<ServiceController> serviceControllers)
    {
        try
        {
            foreach(var service in serviceControllers)
                if (service.Status != ServiceControllerStatus.Running)
                    service.Start();
            RefreshServices();
        }
        catch (Exception ex) { }
    }

    public StopServiceCommand StopServiceCommand { get; set; }
    public void StopService(ObservableCollection<ServiceController> serviceControllers)
    {
        try
        {
            foreach (var service in serviceControllers)
                if (service.Status != ServiceControllerStatus.Stopped &&
                    service.Status != ServiceControllerStatus.StopPending)
                    service.Stop();
            RefreshServices();
        }
        catch (Exception ex) { }
    }

    public RefreshServicesCommand RefreshServicesCommand { get; set; }
    public void RefreshServices()
    {
        Services = Utils.UpdatedServices(SelectedComputer, SelectedCustomer);
    }

    #endregion

    public MainViewModel()
    {
        #region Initialize
        _services = new ObservableCollection<ServiceController>();
        _computerNames = new ObservableCollection<string>();
        _customerNames = new ObservableCollection<string>();
        _selectedComputer = _customerNames.FirstOrDefault();
        _selectedServices = new ObservableCollection<ServiceController>();
        ComputerNames = new ObservableCollection<string> { Environment.MachineName, Environment.MachineName };
        StartServiceCommand = new StartServiceCommand(this);
        StopServiceCommand = new StopServiceCommand(this);
        RefreshServicesCommand = new RefreshServicesCommand(this);
        #endregion
    }
}

最佳答案

您创建了 MainViewModel 的两个实例。每当您在 Stack Overflow 上看到“我的 View 模型中的所有内容都为空,但同时它不是”时,请在 XAML 和构造函数中查找重复的 View 模型实例化。

您莫名其妙地从 Window.Resources 中的一次性副本中获取命令,该副本没有用于其他用途。不要那样做。从这些绑定(bind)中删除 Source={StaticResource viewModel},我认为它们应该按原样工作。

Grid 是 Window 的直接子级,没有自己的 DataContext,所以这应该没问题。如果没有,请告诉我。我们可以毫不费力地让它工作。

<Button Grid.Row="5" Grid.Column="0" Margin="0 4 4 4" Content="Start"
        Command="{Binding StartServiceCommand}"
        CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="1" Margin="4 4 0 4" Content="Stop"
        Command="{Binding StopServiceCommand}"
        CommandParameter="{Binding SelectedItems, ElementName=dataGrid}"/>
<Button Grid.Row="5" Grid.Column="3" Margin="4 4 0 4" Content="Refresh"
        Command="{Binding RefreshServicesCommand}" />

关于c# - 调用命令方法时属性为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56173274/

相关文章:

c# - 服务器套接字在 Close_Wait 中挂起

c# - 我应该将多个项目之间共享的属性放在哪里?

c# - 使用 Excel 工作表作为数据源将测试结果写回 TestContext

c# - Web 浏览器控件在调用表单提交方法时在 IE 中打开下一页

c# - 将 MySql 查询保存到 XML 文件并避免重复

c# - UWP App 在 Windows Phone 上的布局很奇怪

c# - 如何防止 Entity Framework 加载所有子对象

wpf - 更改边框画笔 WPF

WPF 验证不会在 TextBox 的第一个 LostFocus 上触发

c# - WPF多行按钮禁用