Tuesday 12 March 2019

[ReactiveUI] Bind enum to Radio button list using a ListBox

This is an incomplete blog. The code is broke. It's the code I wrote out to ask a technical question. As often I figured it out when I wrote it all out clearly! I've yet to put the corrected code in here! I found it in an editor tab. Rather than toss it away I'll put the working version here. Because the errors I got when it was broke are nested exceptions, which are themselves cryptic.

When your radio buttons depend on something like a enum or a class.

I have a ListBox of RadioButtons and want the Selected RadioButton to bubble up such that the ListBox SelectedItem is the one clicked. Can't see what I'm doing wrong.

View:

  <ListBox x:Name="lstRecordTypes">
    <ListBox.ItemContainerStyle>
      <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
              <RadioButton 
                    Content="{Binding Display}"
                    ToolTip="{Binding Display}"
                    IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent},Path=IsSelected}"/>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
        <Setter Property="Margin" Value="5"/>
      </Style>
    </ListBox.ItemContainerStyle>
  </ListBox>
        public MyView()
        {
            InitializeComponent();
            this.WhenActivated(disposables => this.BindControls(disposables));
        }

        private void BindControls(CompositeDisposable disposableRegistration)
        {
            this.WhenAnyValue(v => v.ViewModel).BindTo(this, v => v.DataContext).AddTo(disposableRegistration);

            this.OneWayBind(ViewModel, vm => vm.RecordTypes,  v => v.lstRecordTypes.ItemsSource)
                .DisposeWith(disposableRegistration);
            this.Bind(ViewModel, vm => vm.SelectedRecordType, v => v.lstRecordTypes.SelectedItem)
                .DisposeWith(disposableRegistration);
            this.BindCommand(ViewModel, vm => vm.SetRecordIndex,
                                              v => v.lstRecordTypes,
                                              nameof(lstRecordTypes.SelectionChanged));
 }

ViewModel:

        private IReactiveList<MyRecordEnumLookup> _recordTypes;
        public IReactiveList<MyRecordEnumLookup> RecordTypes
        {
            get { return _recordTypes; }
            set { this.RaiseAndSetIfChanged(ref _recordTypes, value); }
        }
        
        private MyRecordEnum _selectedRadioRecordType;
        public MyRecordEnum SelectedRadioRecordType
        {
            get { return _selectedRadioRecordType; }
            set { this.RaiseAndSetIfChanged(ref _selectedRadioRecordType, value); }
        }

        public void LoadRecordTypes()
        {
            // Convert a list of enums into a ReactiveList
            var list = ((IList<MyRecordEnum>)Enum.GetValues(typeof(MyRecordEnum)))
                          .Where( e => e != MyRecordEnum.Undefined)
                          .Select(e => new MyRecordEnumLookup(x));

            RecordTypes = new ReactiveList<MyRecordEnumLookup>();
            RecordTypes.AddRange(list);
        }

        public Int32 _selectedRecordTypeInt { get; set; }   // Valid range = 1..5; 0 = Undefined
        public MyRecordEnum SelectedRecordType              // Defaults to Undefined
        {
            get { return (MyRecordEnum)this._selectedRecordTypeInt; }
            set { this._selectedRecordTypeInt = (Int32)value; }
        }

No comments:

Post a Comment