调用命令方法时属性为空

时间:2019-05-16 16:53:25

标签: 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     公共类MainViewModel:INotifyPropertyChanged     {         #region INotify方法         公共事件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
    }
}

1 个答案:

答案 0 :(得分:4)

您创建了MainViewModel的两个实例。每当您在Stack Overflow上看到“即使同时没有,我的viewmodel中的所有内容都为空时”,则在XAML和构造函数中查找重复的viewmodel实例。

您莫名其妙地从Window.Resources的一次性副本中获取了Commands,该副本没有其他用途。不要那样做从这些绑定中删除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}" />