2017-06-13 8 views
0

オブジェクトのプロパティとして数値を格納し、そのビットパターンをWindows Presentation Foundationのチェックボックスのシーケンスとして表示する方法を探していました。これは私が今使っているアプローチで、チェックボックスがチェックされたときに数値の更新があり、番号が変更されたときにチェックボックスが更新されます。これがより簡単な方法で達成できるかどうか教えてください。WPF:チェックボックスのビットフィールドとして数値を表示する方法

MainWindow.xaml.cs

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Media; 
using System.Windows; 
using System.Windows.Controls; 
namespace WPF_Interface_Tests 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public BitField BF { get; set; } 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = this; 
      BF = new BitField(0, 32); 
     } 

     private void Plus_Click(object sender, RoutedEventArgs e) 
     { 
      if (BF.Value < uint.MaxValue) 
       BF.Value += 1; 
     } 

     private void Minus_Click(object sender, RoutedEventArgs e) 
     { 
      if (BF.Value > uint.MinValue) 
       BF.Value -= 1; 
     } 

     private void CheckBox_Click(object sender, RoutedEventArgs e) 
     { 
      SystemSounds.Beep.Play(); 
      var a = (CheckBox)sender; 
      int checkity = 0; 
      if (a.IsChecked.Value) 
       checkity = 1; 
      BF.Value = BF.Value | (uint)(checkity << (int)a.Tag); 
     } 
    } 
    public class Bit : INotifyPropertyChanged 
    { 
     private bool state; 
     public bool State { get { return state; } set { if (this.state != value) { this.state = value; NotifyPropertyChanged("State"); } } } 
     public int Index { get; set; } 
     public Bit() 
     { 
      State = false; 
      Index = 0; 
     } 

     public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(string propName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } 
    } 
    public class BitField : INotifyPropertyChanged 
    { 
     private uint value; 
     public uint Value { get { return value; } set { if (this.value != value) { this.value = value; NotifyPropertyChanged("Value"); UpdateValues(); } } } 
     public byte ByteSize { get; set; } 
     public ObservableCollection<Bit> Values { get; set; } 
     public BitField(uint givenValue, byte givenByteSize) 
     { 
      Value = givenValue; 
      ByteSize = givenByteSize; 
      Values = new ObservableCollection<Bit>(); 
      for (int i = 0; i < ByteSize; i++) 
      { 
       if ((Value | (uint)(1 << i)) == Value) 
        Values.Add(new Bit { State = true, Index = i }); 
       else 
        Values.Add(new Bit { State = false, Index = i }); 
      } 
     } 
     private void UpdateValues() 
     { 
      for (int i = 0; i < Values.Count; i++) 
      { 
       if ((Value | (uint)(1 << i)) == Value) 
        Values[i].State = true; 
       else 
        Values[i].State = false; 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; public void NotifyPropertyChanged(string propName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } 
    } 
} 

MainWindow.xaml

<Window x:Class="WPF_Interface_Tests.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WPF_Interface_Tests" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,201,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=BF.Value, UpdateSourceTrigger=PropertyChanged}"/> 
     <Button x:Name="Minus" Content="-" HorizontalAlignment="Left" Margin="10,229,0,0" VerticalAlignment="Top" Width="20" Click="Minus_Click" /> 
     <ListBox x:Name="LBofChecks" HorizontalAlignment="Left" Height="186" Margin="10,10,0,0" VerticalAlignment="Top" Width="100" ItemsSource="{Binding Path=BF.Values, UpdateSourceTrigger=PropertyChanged}"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <CheckBox IsChecked="{Binding Path=State, Mode=TwoWay}" Tag="{Binding Path=Index}" Click="CheckBox_Click"/> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
     <Button x:Name="Plus" Content="+" HorizontalAlignment="Left" Margin="35,229,0,0" VerticalAlignment="Top" Width="20" Click="Plus_Click" /> 

    </Grid> 
</Window> 

マイアプローチメインウィンドウのプロパティとして新規BitFieldオブジェクトを使用することを含みます。私はDataContext = thisを設定し、次にBitFieldプロパティを構築します。

BitFieldは、Valueプロパティが変更されたときに通知します。 Valueプロパティには、ビットシーケンスを表す数値が格納されます。チェックボックスにバインドするプロパティとして使用する値の一覧については、BitFieldObservableCollection<Bit> Valuesというプロパティを付けます。 Bitオブジェクトのコレクションには、それぞれのオブジェクトが変更されたときに通知されるオブジェクトもあります。また、BitIndexには、BitオブジェクトがObservableCollection<Bit> Valuesの内部に格納されています。 .xamlファイルのCheckBoxテンプレートでは、チェックボックスのTagプロパティをIndexBitに関連付けていることがわかります。

おそらく簡単なアプローチはありますか?

答えて

3

物事のViewModel側では、バインディングのための整数/バイトプロパティを公開するだけです。 intは32ビット値です。議論のために「MyValue」と呼んでください。はい、変更があった場合でも通知します。

ビュー側では、各チェックボックスの "IsChecked"プロパティをMyValueに直接バインドする方法があります。 "ビット"バインディングの場合は、コンバーターを使用します(例:それをBinaryValueToBitConverterと呼んでください。

コンバータはint(またはバイトなど)を受け取り、各チェックボックスごとに真のfalseに変換します。 「bitParamは」(もちろん)渡さConverterParameterある

return (value & (1 << bitParam)) != 0; 

を:キーは、各チェックボックスのためにあなたがConverterParameterとしてチェックボックスのビット位置を使用して、コンバータの変換()メソッドは、単にないことです。

親コントロールのCheckBoxの子インデックスを使用する方法があります。 StackPanel/ListBoxをConverterParameterとして使用します。

希望します

+0

各チェックボックスは特定のオプションを表します。もちろん、ビットとオプションは、数値表現に従って特定の方法で順序付けられます。オプションの意味を変えずに親コントロールのオプションの順序を変更するにはどうすればよいですか?新規オブジェクトを使用するか、チェックボックスオブジェクトを拡張するか、親コントロールの順序の代わりにチェックボックスのタグを使用する以外のアプローチはありますか?これらのオプションのうち、対応するビット位置を決定するには、チェックボックスのタグを使用します。 – Sparky

+0

私はConvertBack()のために何をするだろうので、コンバータを使用しませんでしたか?ああ、どちらの状況でも既存の番号を使用する必要があります。気にしないで。 – Sparky

関連する問題