【问题标题】:Binding Radio Button IsChecked to object's current array of element's state将单选按钮 IsChecked 绑定到对象的当前元素状态数组
【发布时间】:2017-02-23 17:27:22
【问题描述】:

我正在使用 C#/WPF/MVVM 开发一个小型实用程序,它允许设置我们用于测试的控制器的输入状态。我正在开发的应用程序和硬件/我们的网络服务与硬件之间的通信只是一种方式,这意味着应用程序将只能设置输入的状态,但不能获取状态。

另外一点要提到的是,在我们解决方案的其他部分中已经为此定义了一些类型,这些都在 F# 中。为了做我的应用程序,我目前正在使用 C#。所以我做了一个Unit 类来包装F# 中定义的LocalControllerTypes.LocalController 类型,包含很多需要的信息。

为了做到这一点,我有一个 enum 枚举可能的 InputState(目前有 ActiveNormal,但该列表可能会随着时间的推移而增长)。此外,每种单元类型上的输入数量不同(有些有 2 个,有些有 4 个,有些有更多),所以我在所选单元的 Inputs 数组上绑定了一个 ItemControl,不幸的是,它只包含我必须显示的输入的名称。该单元还有 2 个与它的输入相关的其他属性,InputWriters,这是一个类型的数组,用于将命令发送到与该硬件通信的硬件/Web 服务,以及InputStates,这是一个InputState 的数组,用于每个输入,最后在应用程序中设置(因为我们无法从硬件获取状态)。

现在我想将单选按钮的IsChecked 属性(我定义为ItemsControlItemTemplate)绑定到当前SelectedUnitInputState(在我的ViewModel 中) . 我遇到的问题,是我需要知道单选按钮是针对SelectedUnitInputs 数组的哪个索引,以便在相同索引处获取项目对于SelectedUnitInputStates 属性。

有什么办法可以做到吗?

MainWindow.xaml:

            ...
            <ItemsControl  Grid.Row="1" ItemsSource="{Binding SelectedUnit.LocalControllerInfo.Inputs}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Margin="10" FontSize="15" Style="{StaticResource TextBlockNormalBase}" Text="{Binding InputName}"/>
                            <StackPanel Orientation="Horizontal">
                                <RadioButton Margin="10" Foreground="White" Content="Normal"
                                             IsChecked="{Binding Path=?,
                                                                Converter={StaticResource inputToBoolConverter},
                                                                ConverterParameter=?}"/>
                                <RadioButton Margin="10" Foreground="White" Content="Active"
                                             IsChecked="{Binding Path=?,
                                                                Converter={StaticResource inputToBoolConverter},
                                                                ConverterParameter=?}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
            ...

Unit.cs:

public class Unit : BindableObject
{
    public enum InputState
    {
        Normal,
        Active
    }

    private LocalControllerTypes.LocalController _localControllerInfo;
    private LocalControllerTypes.ArduinoInjector[] _arduinoInjector;
    private WebWriter.WebWriter[] _inputWriters;
    private SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection _networkSwitchConnection;
    private InputState[] _inputStates;
    private bool _isUnitConnected;

    public Unit(LocalControllerTypes.LocalController localControllerInfo,
        LocalControllerTypes.ArduinoInjector[] arduinoInjector,
        WebWriter.WebWriter[] inputWriters,
        SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection networkSwitchConnection)
    {
        _localControllerInfo = localControllerInfo;
        _arduinoInjector = arduinoInjector;
        _inputWriters = inputWriters;
        _networkSwitchConnection = networkSwitchConnection;
        // This assumption might not always be true, but there is no way for now to get the input state
        _inputStates = Enumerable.Repeat(InputState.Normal, _inputWriters.Length).ToArray();
        // This assumption might not always be true, but there is no way for now to get the connection state
        _isUnitConnected = true;
    }

    public LocalControllerTypes.LocalController LocalControllerInfo
    {
        get
        {
            return _localControllerInfo;
        }
        set
        {
            if (_localControllerInfo != value)
            {
                _localControllerInfo = value;
                RaisePropertyChanged();
            }
        }
    }

    public LocalControllerTypes.ArduinoInjector[] ArduinoInjectors
    {
        get
        {
            return _arduinoInjector;
        }
        set
        {
            if (_arduinoInjector != value)
            {
                _arduinoInjector = value;
                RaisePropertyChanged();
            }
        }
    }

    public WebWriter.WebWriter[] InputWriters
    {
        get
        {
            return _inputWriters;
        }
        set
        {
            if (_inputWriters != value)
            {
                _inputWriters = value;
                RaisePropertyChanged();
            }
        }
    }

    public SNMPNetworkSwitchConnection.SNMPNetworkSwitchConnection NetworkSwitchConnection
    {
        get
        {
            return _networkSwitchConnection;
        }
        set
        {
            if (_networkSwitchConnection != value)
            {
                _networkSwitchConnection = value;
                RaisePropertyChanged();
            }
        }
    }

    public InputState[] InputStates
    {
        get
        {
            return _inputStates;
        }
        set
        {
            if (_inputStates != value)
            {
                _inputStates = value;
                RaisePropertyChanged();
            }
        }
    }

    public bool IsUnitConnected
    {
        get
        {
            return _isUnitConnected;
        }
        set
        {
            if (_isUnitConnected != value)
            {
                _isUnitConnected = value;
                RaisePropertyChanged();
            }
        }
    }
}

MainViewModel.cs:

public class MainViewModel : INotifyPropertyChanged
{
    private Unit _selectedUnit;
    private ObservableCollection<Unit> _units;
    private string _reader1RawCardData;
    private string _reader2RawCardData;
    private int _reader1BitsCount;
    private int _reader2BitsCount;

    public event PropertyChangedEventHandler PropertyChanged;

    public MainViewModel(IUnitStore unitStore)
    {
        UnitStore = unitStore;

        // We could use directly the unitstore instead of creating another container and binding on that, but
        // not doing so will allow us to add unit filtering further down the road
        _units = new ObservableCollection<Unit>(unitStore.Units);
        _selectedUnit = _units.First();

        _reader1RawCardData = "";
        _reader2RawCardData = "";
        _reader1BitsCount = 0;
        _reader2BitsCount = 0;
    }

    protected void RaisePropertyChanged([CallerMemberName]string propertName = "")
    {
        var temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(propertName));
        }
    }

    protected void RefreshUnitStore(object obj)
    {
        UnitStore.UpdateStore();
        Units = new ObservableCollection<Unit>(UnitStore.Units);
        SelectedUnit = Units.First();
    }

    protected void SendReaderCardSwipe(object obj)
    {
        int unitReaderNumber = (int)obj;
        IPAddress arduinoIp = SelectedUnit.LocalControllerInfo.Readers[unitReaderNumber - 1].InjectorIp;
        int injectorNumber = SelectedUnit.LocalControllerInfo.Readers[unitReaderNumber - 1].InjectorNumber;
        string serviceUrl = SelectedUnit.ArduinoInjectors.Where(injector => injector.Ip.Equals(arduinoIp)).First().Url;

        InjectorInterface.CardSwipe<IPAddress>(serviceUrl, arduinoIp, injectorNumber, Reader1BitsCount, Reader1RawCardData);
    }

    protected void UpdateSelectedUnitConnectionState(object obj)
    {
        ((INetworkConnection.INetworkConnection)SelectedUnit.NetworkSwitchConnection).SetConnection(SelectedUnit.IsUnitConnected);
    }

    public IUnitStore UnitStore
    {
        get;
        private set;
    }

    public Unit SelectedUnit
    {
        get
        {
            return _selectedUnit;
        }
        set
        {
            if (_selectedUnit != value)
            {
                _selectedUnit = value;
                RaisePropertyChanged();
            }
        }
    }

    public ObservableCollection<Unit> Units
    {
        get
        {
            return _units;
        }
        set
        {
            if (_units != value)
            {
                _units = value;
                RaisePropertyChanged();
            }
        }
    }

    public string Reader1RawCardData
    {
        get
        {
            return _reader1RawCardData;
        }
        set
        {
            if (_reader1RawCardData != value)
            {
                _reader1RawCardData = value;
                RaisePropertyChanged();
            }
        }
    }

    public string Reader2RawCardData
    {
        get
        {
            return _reader2RawCardData;
        }
        set
        {
            if (_reader2RawCardData != value)
            {
                _reader2RawCardData = value;
                RaisePropertyChanged();
            }
        }
    }

    public int Reader1BitsCount
    {
        get
        {
            return _reader1BitsCount;
        }
        set
        {
            if (_reader1BitsCount != value)
            {
                _reader1BitsCount = value;
                RaisePropertyChanged();
            }
        }
    }

    public int Reader2BitsCount
    {
        get
        {
            return _reader2BitsCount;
        }
        set
        {
            if (_reader2BitsCount != value)
            {
                _reader2BitsCount = value;
                RaisePropertyChanged();
            }
        }
    }

    public ICommand RefreshSourceCommand
    {
        get
        {
            return new RelayCommand(RefreshUnitStore);
        }
    }

    public ICommand SendReaderCardSwipeCommand
    {
        get
        {
            return new RelayCommand(SendReaderCardSwipe);
        }
    }

    public ICommand UpdateSelectedUnitConnectionStateCommand
    {
        get
        {
            return new RelayCommand(UpdateSelectedUnitConnectionState);
        }
    }
}

【问题讨论】:

    标签: c# .net wpf mvvm data-binding


    【解决方案1】:

    您的ItemsControl 绑定到SelectedUnit.LocalControllerInfo.Inputs.Inputs的类型是什么?

    正如所写,您的绑定将无法访问InputStateInputName。这并不真正在“如何识别什么数组项与什么枚举”的范围内

    要解决您最初的问题,一种可能性是嵌套一些元组并绑定到它,一个拉

    List<Tuple<int,State>> States = new List<Tuple<int,State>>();
    
    States.Add(new Tuple<int, State>(1,State.Bar));
    States.Add(new Tuple<int, State>(2, State.Foo));
    States.Add(new Tuple<int, State>(3, State.Bar));
    

    【讨论】:

      猜你喜欢
      • 2014-06-06
      • 1970-01-01
      • 2021-05-24
      • 2016-04-10
      • 1970-01-01
      • 2010-12-04
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多