【问题标题】:Properties are null when calling a command method调用命令方法时属性为空
【发布时间】:2019-05-16 16:53:24
【问题描述】:

当调用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
    }
}

【问题讨论】:

  • 如果注释掉相等检查并从 Setfield 返回会怎样?
  • 值仍然为空。
  • 调试问题是什么意思?是的,我有,它的绑定和构建一切都很好。一旦应用程序运行并单击刷新(或在服务停止或启动后调用刷新),我需要的两个值都是 null。
  • 所以我假设public void RefreshServices() 这是运行的,在里面设置一个断点,先检查值,然后步骤,值是否改变了?如果是这样,Utils.UpdatedServices 这是在做什么?
  • 您创建了两个 MainViewModel 实例。莫名其妙地,您从一个没有其他用途的一次性副本中获取命令。不要那样做。只需从这些绑定中删除 Source={StaticResource viewModel}

标签: c# .net wpf mvvm


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-28
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    相关资源
    最近更新 更多