Как я могу привязать 8 флажков в MainWindow.xaml к каждому биту свойства байта ViewModel? - PullRequest
0 голосов
/ 13 марта 2020

Я довольно новичок в WPF и MVVM. Я пытаюсь добиться того, чтобы в моем GUI было восемь флажков, которые мне нужно преобразовать в одно байтовое значение, чтобы я мог последовательно передавать его в любой момент времени. Должен ли я создать 8 свойств bool, а затем преобразовать их в байтовое свойство?

В настоящее время это мой XAML. Я привязал каждый флажок индивидуально к свойству байта. Можно ли как-то связать их все с одним свойством, чтобы сделать байт, где каждый флажок представляет немного.

<Window x:Class="ModelClassTest.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="{Binding Title}" Height="350" Width="525">
    <Grid>
        <ContentControl prism:RegionManager.RegionName="ContentRegion" />
        <CheckBox Margin="10,10,0,0"  Content="Bit 0" IsChecked="{Binding Path Bit0}"/>
        <CheckBox Margin="10,30,0,0" Content="Bit 1" IsChecked="{Binding Path Bit1}"/>
        <CheckBox Margin="10,50,0,0" Content="Bit 2" IsChecked="{Binding Path Bit2}"/>
        <CheckBox Margin="10,70,0,0" Content="Bit 3" IsChecked="{Binding Path Bit3}"/>
        <CheckBox Margin="10,90,0,0" Content="Bit 4" IsChecked="{Binding Path Bit4}"/>
        <CheckBox Margin="10,110,0,0" Content="Bit 5" IsChecked="{Binding Path Bit5}"/>
        <CheckBox Margin="10,130,0,0" Content="Bit 6" IsChecked="{Binding Path Bit6}"/>
        <CheckBox Margin="10,150,0,0" Content="Bit 7" IsChecked="{Binding Path Bit7}"/>
        <Button Width="100" Height="20" Margin="10,173,408.723,128.076" Content="Transmit" Command="{Binding ClickMe}"/>
    </Grid>
</Window>

Ответы [ 2 ]

2 голосов
/ 13 марта 2020

Вместо создания флажков вручную, вы можете создать ItemsControl для всех битов вашего байта. Представьте байт списком одиночных битов.

Создайте класс модели представления для бита сиглы:

// The ViewModelBase base class implements INotifyPropertyChanged
// and provides the SetProperty method
class Bit : ViewModelBase 
{
    private bool _isSet;

    public Bit(int bitNumber)
    {
        BitNumber = bitNumber;
    }

    public int BitNumber { get; }

    public bool IsSet
    {
        get => _isSet;
        set => SetProperty(ref _isSet, value);
    }
}

Вот ваш байт в основной модели представления:

public IReadOnlyCollection<Bit> Byte { get; }
    = new List<Bit>(Enumerable.Range(0, 8).Select(v => new Bit(v)));

В основной модели представления создайте ICommand, который преобразует ваш список битов в байт и будет использовать это значение. Либо создайте свойство типа byte, которое будет вычислять значение «на лету» на основе единичных битов. Вот как может выглядеть реализация:

void UseByte()
{
    var byteValue = Byte.Select((v, i) => (1 << i) * (v.IsSet ? 1 : 0)).Sum();

    // use the value as needed
}

А вот так может выглядеть ваша точка зрения:

<ItemsControl ItemsSource="{Binding Byte}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding IsSet}">
                <TextBlock>
                    <Run Text="Bit "/><Run Text="{Binding BitNumber, Mode=OneTime}"/>
                </TextBlock>
            </CheckBox>        
         </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
1 голос
/ 13 марта 2020

Вам просто нужно использовать привязку с подключенным преобразователем, чтобы прочитать значение байта из модели представления, и ICommand для переключения указанного бита c в байте:

ByteToBitConverter.cs

class ByteToBiteConverter : IValueConverter
{    
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => 
    value is byte byteValue 
      && int.TryParse(parameter.ToString(), out int bitPosition)
        ? new BitArray(new Byte[] {byteValue}).Get(bitPosition - 1)
        : Binding.DoNothing;

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    => throw new NotSupportedException();  
}

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{ 
  private byte byteValue;
  public byte ByteValue 
  {
    get => this.byteValue;
    set
    {
      this.byteValue = value;
      OnPropertyChanged();
    }
  }

  public ICommand ToggleBitCommand => new RelayCommand(ToggleBit);
  public int BitCount { get; set; }

  public ViewModel()
  {
    this.ByteValue = 128;
  }

  private void ToggleBit(object commandParameter)
  {
    if (!int.TryParse(commandParameter.ToString(), out int bitPosition))
    {
      return;
    }

    var bytes = new Byte[] { this.ByteValue };
    var boolArray = new bool[this.BitCount];
    var bits = new BitArray(bytes);
    int toggleBitIndex = bitPosition - 1;

    bits.Set(toggleBitIndex, !bits.Get(toggleBitIndex));

    bytes = new Byte[1];
    bits.CopyTo(bytes, 0);
    this.ByteValue = bytes.FirstOrDefault();
  }

  #region INotifyPropertyChanged

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

  #endregion
}

RelayCommand.cs
(реализация взята из Документы Microsoft: ретрансляция журнала команд c)

public class RelayCommand : ICommand
{
    #region Fields 
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;
    #endregion // Fields 
    #region Constructors 
    public RelayCommand(Action<object> execute) : this(execute, null) { }
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        _execute = execute; _canExecute = canExecute;
    }
    #endregion // Constructors 
    #region ICommand Members 
    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    public void Execute(object parameter) { _execute(parameter); }
    #endregion // ICommand Members 
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ByteToBitByteConverter />
  </Window.DataContext>

  <Window.Resources>
    <ViewModel />
  </Window.Resources>

  <StackPanel>

    <!-- 
      CommandParameter is the bit position. 
      Binding.Mode of IsChecked has to be explicitely set to BindingMode.OneWay
    -->
    <CheckBox x:Name="Bit0" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="1" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=1}" />
    <CheckBox x:Name="Bit1" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="2" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=2}" />
    <CheckBox x:Name="Bit2" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="3" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=3}" />
    <CheckBox x:Name="Bit3" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="4" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=4}" />
    <CheckBox x:Name="Bit4" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="5" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=5}" />
    <CheckBox x:Name="Bit5" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="6" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=6}" />
    <CheckBox x:Name="Bit6" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="7" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=7}" />
    <CheckBox x:Name="Bit7" 
              Command="{Binding ToggleBitCommand}"
              CommandParameter="8" 
              IsChecked="{Biding ByteValue, Mode=OneWay, Converter={StaticResource ByteToBitConverter}, ConverterParameter=8}" />
  </StackPanel>
</Window>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...