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; }
        }

[ReactiveUI] Test command

Testing ReactiveUI Commands is almost screaming Tell don't Ask at you.

I suppose may want to set a state on completion of the method invoked when executing the Command. e.g. DoExitViewModel(), in the example. But only do this when the view needs to know a result. In this example you would've Disposed() any ViewModel dependencies; so the View can now close itself.

Do not set a property in the ViewModel just so that you test whether production code successfully completed. Use Tell Don't Ask instead.

Commands can rarely send data from the View to ViewModel. When a ViewModel needs to know under what state a Command was invokde, one would normally set a property before invoking a Command. In contrast, when the view needs to know a result, I'll always try to return that result to the view from the method executing in the ViewModel.

 public partial class MyView : Window, IViewFor<MyViewModel>
 {

    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(MyViewModel)
                                               , typeof(MyView));

    public MyViewModel ViewModel
    {
        get { return (MyViewModel)this.GetValue(ViewModelProperty); }
        set { this.SetValue(ViewModelProperty, value); }
    }

    object IViewFor.ViewModel
    {
        get { return this.ViewModel; }
        set { this.ViewModel = (MyViewModel)value; }
    }

    public partial class 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.BindCommand(this.ViewModel, vm => vm.ExitView,
                                          v => v.btnExit)
            .AddTo(disposableRegistration);

        this.ViewModel.ExitView.Subscribe(success => { if (success) this.Close(); });

        this.WhenAnyObservable(v => v.ViewModel.BarcodeScanned)
            .Subscribe(authenticationType => this.ShowAuthentication(authenticationType));


    }
}

public class MyViewModel
{
    public ReactiveCommand<Unit, bool> ExitView { get; private set; }            // Output to view
    public ReactiveCommand<Unit, CRUDResult> AddTemplate { get; private set; }   // Output
    public ReactiveCommand<string, AuthenticationTypes?> BarcodeScanned { get; } // Input from view + Output
    public ReactiveCommand<Unit, Unit> Boring { get; }                           // No input/output from/to view

    public IObservable<bool> CanAddTemplate { get; private set; }

    public MyViewModel()
    {

        this.CanAddTemplate = (this).WhenAnyValue(vm => vm.PageState, (EditState status) => status == EditState.Browse);
        
        this.AddTemplate = ReactiveCommand.Create(() => this.DoAddTemplate(), this.CanAddTemplate);
        this.BarcodeScanned = ReactiveCommand.Create<string, AuthenticationTypes?>(barcode => this.DoBarcodeScanned(barcode));
        this.ExitView = ReactiveCommand.CreateFromTask(async () => await Task.Run(() => this.DoExitViewModel()));
    }
    
    public bool DoExitViewModel()
    {
        // Dispose the ViewModel
        return true;
    }

    private CRUDResult DoAddTemplate()
    {
        // Do whatever you do
        this.PageState = EditState.Add;
        return new CRUDResult(null);
    }
    
    private AuthenticationTypes? DoBarcodeScanned(string barcode)
    {
        return null;
    }

}

public class MyViewModelTests
{
    [Test]
    public void Add_Button_Test()
    {
        // Arrange
        var vm = new MyViewModel();
        vm.Setup(0);
        EditState expectedStatus = EditState.Add;
        
        CRUDResult resultPage = new CRUDResult(null);

        // Act
        vm.AddTemplate.Subscribe(tf => resultPage = tf);
        vm.AddTemplate.Execute().Subscribe();

        // Assert
        Assert.AreEqual(expectedStatus, vm.PageState);
        Assert.AreEqual(null, resultPage.Message);
    }
}

Wpf custom dictionary. Notes

Wpf uses #LID to indicate the language or dialect of the dictionary which it will pick up from the current localization.

e.g.
#LID 2057 = UK location

Must include

  1. the System namespace in xaml,
  2. SpellCheck.IsEnabled="True" in the control,
  3. location of the dictionary.

Best set build action of the dictionary to embedded resource.

<Window ...
  xmlns:sys="clr-namespace:System;assembly=System">
  <!-- Must include System namespace in xaml -->

  <TextBox SpellCheck.IsEnabled="True">
    <SpellCheck.CustomDictionaries>
      <!-- List of dictionaries to use -->
      <!-- hard-coded -->
      <sys:Uri>c:\pathToDictionary\uk.lex</sys:Uri>
      <!-- OR: Embedded resource -->
      <sys:Uri>pack://application:,,,/MyWpfProject;component/uk.lex</sys:Uri>
      <!-- Must set uk.lex  Build Action = Embedded Resource -->
    </SpellCheck.CustomDictionaries>
  </TextBox>

MyWpfProject - being the name of the application, in this example.

Tuesday, 26 February 2019

[ReactiveUI] Bind a list of enums to WPF combo

Originally posted by: Mitkins, at: Oct 12 '17 at 0:22, at stackoverflow. I edited it to correct minor typos in the original. And to make one of two alterations.

I am trying to find a simple example where the enums are shown as is. All examples I have seen tries to add nice looking display strings but I don't want that complexity. Note: EffectStyle is just an enum.

public enum EffectStyle { Undefined = 0, Yes = 1, No = 2 }

Basically I have a class that holds all the properties that I bind, by first setting the DataContext to this class, and then specifying the binding like this in the xaml file:

<ComboBox ItemsSource="{Binding Path=EffectStyle}"/>

But this doesn't show the enum values in the ComboBox as items.


Using ReactiveUI, I've created the following alternate solution. It's not an elegant all-in-one solution, but I think at the very least it's readable.

In my case, binding a list of enum to a control is a rare case, so I don't need to scale the solution across the code base. However, the code can be made more generic by changing EffectStyleLookup.Item into an Object. I tested it with my code, no other modifications are necessary. Which means the one helper class could be applied to any enum list. Though that would reduce its readability - ReactiveList<EnumLookupHelper> doesn't have a great ring to it.

Using the following helper class:

public class EffectStyleLookup
{
    public EffectStyle Item { get; set; }
    public string Display { get { return Item.ToString();} }

    public EffectStyleLookup(){ }

    public EffectStyleLookup(EffectStyle item)
    {
        this.Item = item;
    }
}

Yes. I prefer using constructors. All things considered, you write less code.

In the ViewModel, convert the list of enums and expose it as a property:

public MyViewModel : ReactiveObject
{
  private ReactiveList<EffectStyleLookup> _effectStyles;
  public ReactiveList<EffectStyleLookup> EffectStyles
  {
    get { return _effectStyles; }
    set { this.RaiseAndSetIfChanged(ref _effectStyles, value); }
  }

  // See below for more on this
  private EffectStyle _selectedEffectStyle;
  public EffectStyle SelectedEffectStyle
  {
    get { return _selectedEffectStyle; }
    set { this.RaiseAndSetIfChanged(ref _selectedEffectStyle, value); }
  }

  public MyViewModel()
  {
    this.LoadEffectStyleCombo();
  }

  private void LoadEffectStyleCombo()
  {
    // Convert a list of enums into a ReactiveList
    var xs = ((IList<EffectStyle>)Enum.GetValues(typeof(EffectStyle)))
                  .Select( x => new EffectStyleLookup(x) );

    EffectStyles = new ReactiveList<EffectStyleLookup>();
    EffectStyles.AddRange(xs);
  }
}

In the ComboBox, utilise the SelectedValuePath property, to bind to the original enum value:

<ComboBox x:Name="cboEffectStyle" DisplayMemberPath="Display" SelectedValuePath="Item" />

In the View, this allows us to bind the original enum to the SelectedEffectStyle in the ViewModel, but display the ToString() value in the ComboBox:


public MyView()
{
    InitializeComponent();
    this.WhenActivated(disposables => this.BindControls(disposables));
}

private void BindControls(CompositeDisposable disposableRegistration)
{
    this.OneWayBind(ViewModel, vm => vm.EffectStyles, v => v.cboEffectStyle.ItemsSource).DisposeWith(disposableRegistration);
    this.Bind(ViewModel, vm => vm.SelectedEffectStyle, v => v.cboEffectStyle.SelectedValue).DisposeWith(disposableRegistration);
}

Thursday, 28 June 2018

[ReactiveUI] Auto Complete Incremental Search?

A Winforms UserControl had an incremental search TextBox and a list. A detail view is set from the selected value in the list. This works when I click on a particular list item.

I want to get the last string value from the incremental AutoCompleteSearch TextBox too. To fire a command and also set the user in the Detail view. But:

 Couldn't find a Command Binder for System.Windows.Forms.AutoCompleteStringCollection 

listUsers is the compound UserControl with a property SearchAutoCompleteCustomSource:

    public AutoCompleteStringCollection SearchAutoCompleteCustomSource
    {
        get { return tbAutoCompleteSearch.AutoCompleteCustomSource; }
        set { tbAutoCompleteSearch.AutoCompleteCustomSource = value; }
    }

MyView:

    this.BindCommand(this.ViewModel, vm => vm.UserToFind,
                                      v => v.listUsers.SearchAutoCompleteCustomSource);

MyViewModel:

private readonly ReactiveCommand userToFind;
public ReactiveCommand UserToFind => this.userToFind;

public MyViewModel()
{
    this.userToFind = ReactiveCommand.Create(userName => this.SetUserSelected(userName));
}

private bool SetUserSelected(string userName)
{
    User user = userManager.GetUserByName(userName);
    bool userFound = (user != null);

    if (userFound)
    {
        SetDetailView(user);
    }
    return userFound;
}

Saturday, 13 May 2017

Epub3 conversion notes.

(1) I found this list of epub2 to epub3 conversion notes

Notes below are mine, with typical error messages returned by epubcheck validation.

(2) 'Exactly one manifest item must declare the 'nav' property (number of 'nav' items: 0).'

For Epub 3, this means you need a table of contents in an xhtml file. An ebook often comes with an html "table of contents".

You should convert it to the required format. See the example below.

Your table of contents should look something like this:

    <nav epub:type="toc" id="toc">
        <ol id="nav">
            <li><a href="chapter01.xhtml#myId">Some entry</a></li>
            <li><a href="chapter02.xhtml#myOtherId">Some other entry</a></li>
              ...
        </ol>
    </nav>

The <nav> tag is a special epub tag, so the html tag, it sits in, needs another namespace to tell it what a <nav> is:

    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:epub="http://www.idpf.org/2007/ops"
          xml:lang="en">

Last: The <ol> tags inside your <nav> entry must not be nested (in more <ul>, or <ol> lists. One flat list only. You must use an <ol> list. <ul> not allowed.

So give this ol a style in your stylesheet. To knock out the numbers:

    ol#nav { list-style-type: none; }

In an example where "p2.xhtml" has a table of contents, .opf entry changes from:

    <item id="toc" media-type="application/xhtml+xml" 
          href="toc.xhtml" />

to:

    <item id="toc" media-type="application/xhtml+xml" 
          href="toc.xhtml" properties="nav"/>

[ PS: if you also have an svg file, add properties="svg" to that in the .opf too! ]

Pesky epub3!

Monday, 24 April 2017

Locating an element to test with FlaUI

The WinForms application I'm trying to test is legacy in more ways than I'd like.

Here is FlaUI Inpect looking at a login form I want to test. I need access to 4 items. Each has an AutomationId. The ids are: textUser, textPINCode, buttonHalt, buttonLogin

These 4 controls are custom controls derived from Krypton controls. I think the Krypton controls derive from Windows Forms 2.0

Suppose I have a handle on the top level window ("FormSplashScreen"). What is the XPath to get one of the 4 I want (say textUser)?