I have a combobox with a custom enum (just true/false). I have a function that checks conditions if the SelectedValue changes from false to true and if the conditions are wrong it changes the combobox SelectedValue back to false. This changes the SelectedValue to false if you check it in code, but when you look at the UI it's still on true.
Here's the xaml for the combobox:
<ComboBox x:Name="comboEnabled1" Width="80" Height="26"
ItemsSource="{Binding Path=TrueFalseChoices}"
SelectedValue="{Binding Path=Enable1, Mode=TwoWay}"/>
Here's the viewmodel
private TrueFalse _enable1 = TrueFalse.False;
public TrueFalse Enable1
{
get { return _enable1; }
set
{
if (_enable1 != value)
{
_enable1 = value;
base.OnPropertyChanged("Enable1");
OnEnableChanged(EventArgs.Empty);
}
}
}
And here's the function that I'm using to check the conditions
public void HandleEnable(object sender, EventArgs e)
{
if(Enable1 == TrueFalse.True)
{
if(!connected)
{
HandleMessage("Can't enable, not connected");
Enable1 = TrueFalse.False;
}
else if (!_main.CBCheck(_main.cbReason))
{
Enable1 = TrueFalse.False;
}
}
Console.WriteLine("Enabled {0}", Enable1);
}
Was thinking I'm changing the value too rapidly, but the last Console.Writeline produces the right outcome each time.
Any help appreciated!
Edit: Calling Handleenable here:
protected void OnEnableChanged(EventArgs e)
{
EventHandler handler = EnableChanged;
if (handler != null)
handler(this, e);
}
And in the ViewModel funct:
EnableChanged += HandleEnable;
Changing the Enable1 in any other place worked as it should have, only having issues in HandleEnable function.Also tried changing other comboboxes in the HandleEnable function and that worked as it should have.
I would recommend actually disabling the ComboBox if the requirements are not met.
But if you insist on reverting Enable1 back to False if conditions are not met, you should push the notification properly through the dispatcher.
set
{
var effectiveValue = condition ? value : TrueFalse.False;
if (effectiveValue == TrueFalse.False && value == TrueFalse.True)
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(
new Action(() => base.OnPropertyChanged("Enable1"), null));
//your regular set-code follows here
}
It happens because WPF is already responding to that event, and therefore ignoring the subsequent calls until it's done. So you immediately queue another pass as soon as the current one is finished.
But I would still recommend disabling the ComboBox when it is effectively disabled. Accessing the dispatcher from a viewmodel does not smell good no matter how you look at it.
UPD: You can also solve that with {Binding Enable1, Delay=10} if your framework is 4.5.1+.
Related
SOLUTION IS IN EDIT OF THE ACCEPTED ANSWER
I have a view in which has two Pickers, I need to have it so that when the SelectedItem property in one Picker changes, the list of Items in the second Picker (ItemSource) changes as well.
Currently I have a bound the SelectedItem and SelectedIndex properties of both pickers to properties in my ViewModel. In the setter(s) for both of them, I perform the logic needed to change the list of Items in the second picker. The list of Items in the second picker changes successfully, but when I set the SelectedIndex (to make it select an Item by default), this fails if the index which I am setting it to is the same as the index which it was on in the previous list. It just shows the Title of the Picker instead, this issue seems to be related to this bug.
My Code:
Both Pickers are bound to an Observable collection of strings FYI
FrameType and DirectionType are Enums
I initially used only the SelectedItem property
Relevant XAML
<Label Grid.Row="1" Grid.Column="0" VerticalTextAlignment="Center"
Text="Direction: " />
<Picker x:Name="PickerDirection" Grid.Row="1" Grid.Column="1"
Title="Select Direction"
ItemsSource="{Binding Directions}"
SelectedItem="{Binding SelectedDirection}"
SelectedIndex="{Binding SelectedDirectionIndex}"></Picker>
<Label Grid.Row="2" Grid.Column="0" VerticalTextAlignment="Center"
Text="Frame: "/>
<Picker x:Name="PickerFrame" Grid.Row="2" Grid.Column="1"
Title="Select Frame"
ItemsSource="{Binding Frames}"
SelectedItem="{Binding SelectedFrame}"
SelectedIndex="{Binding SelectedFrameIndex}"></Picker>
Relevant View Model code:
public string SelectedDirection
{
get { return _selectedDirection; }
set
{
if (Directions.Contains(value))
{
if (_selectedDirection != value)
{
if (EnumUtils.ToEnumFromString<FrameType>(SelectedFrame) == FrameType.Road &&
!DirectionsRoad.Contains(value))
{
_selectedDirection = Directions[Directions.IndexOf(DirectionType.Right.ToString())];
}
else
{
_selectedDirection = value;
}
OnPropertyChanged();
}
}
}
}
public string SelectedFrame
{
get { return _selectedFrame; }
set
{
if (_selectedFrame != value)
{
_selectedFrame = value;
if (EnumUtils.ToEnumFromString<FrameType>(_selectedFrame) == FrameType.Road)
{
Directions = DirectionsRoad;
if (Directions.Contains(SelectedDirection))
{
SelectedDirectionIndex = Directions.IndexOf(SelectedDirection);
}
else
{
SelectedDirectionIndex = Directions.IndexOf(DirectionType.Right.ToString());
}
}else if (EnumUtils.ToEnumFromString<FrameType>(_selectedFrame) == FrameType.Lane)
{
Directions = DirectionsAll;
SelectedDirectionIndex = Directions.IndexOf(SelectedDirection);
}
OnPropertyChanged();
}
}
}
}
public int SelectedDirectionIndex
{
get { return _selectedDirectionIndex; }
set
{
if (_selectedDirectionIndex != value)
{
if (!(value < 0 || value >= Directions.Count))
{
_selectedDirectionIndex = value;
OnPropertyChanged();
}
}
}
}
public int SelectedFrameIndex
{
get { return _selectedFrameIndex; }
set
{
if (_selectedFrameIndex != value)
{
if (!(value < 0 || value >= Frames.Count))
{
_selectedFrameIndex = value;
OnPropertyChanged();
}
}
}
}
The outcome:
I expect it to never be empty since I ensure that the SelectedDirection is always set to something.
Notes:
I initially used just the SelectedItem property, but when I encountered this bug I thought using the SelectedIndex property would help to fix it.
I used ObservableCollection to maintain consistency with the other viewModels in the project, and to ensure that the options in the picker are updated when I make changes (based on my understanding you need to use ObservableCollection to make this possible).
I do plan to refactor the code in the setter for SelectedFrame into smaller functions as soon as I get things to work.
Due to this It seems that using the SelectedIndexChanged event of the Picker would be the only way to fix this. However the comment by ottermatic in this question says that events are unreliable. Hence I felt is was better to perform this logic in the setter.
If someone could comment on what I may be doing wrong in my code which is causing this issue and also comment on the pros/cons and/or whether or not I should use the eventHandler or have the logic in my setter. Thanks
I don't really see why you are using both SelectedItem and SelectedIndex, but I think what you are trying to achieve can be achieved easier.
First of all, I don't think you need ObservableCollection types at all in your example, since you are setting the directions anyway and not modifying the collection. More importantly, fiddling around with the indices is completely unnecessary, as far as I can tell. You are using strings anyway and even though String is not a value type, but a reference type, you cannot practically distinguish two String instances that have the same content, hence assinging the respective values to SelectedDirection and SelectedFrame is sufficient.
The following checks seem redundant to me
if (Directions.Contains(value))
if (EnumUtils.ToEnumFromString<FrameType>(SelectedFrame) == FrameType.Road &&
!DirectionsRoad.Contains(value))
since Directions are set to DirectionsRoad anyway if SelectedFrame has been set to "Road". Hence I'd assume that the second condition won't evaluate to true in any case. Hence the SelectedDirection can be simplified:
public string SelectedDirection
{
get => _selectedDirection;
set
{
if (_selectedDirection != value && Directions.Contains(value))
{
_selectedDirection = value;
OnPropertyChanged();
}
}
}
Within the setter of SelectedFrame there are many things going on, which I'd refactor to methods on it's own right, to improve clarity.
public string SelectedFrame
{
get => _selectedFrame;
set
{
if (_selectedFrame != value)
{
_selectedFrame = value;
UpdateAvailableDirections();
OnPropertyChanged();
}
}
}
private void UpdateAvailableDirections()
{
// store the selected direction
var previouslySelectedDirection = SelectedDirection;
Directions = GetValidDirectionsByFrameType(EnumUtils.ToEnumFromString<FrameType>(SelectedFrame));
SelectedDirection = GetSelectedDirection(previoslySelectedDirection, Directions);
}
private string[] GetValidDirectionsByFrameType(FrameType frameType)
{
return frameType == FrameType.Road ? DirectionsRoad : DirectionsAll;
}
private string GetSelectedDirection(string previouslySelectedDirection, string[] validDirections)
{
return validDirections.Contains(previouslySelectedDirection) ? previouslySelectedDirection : DefaultDirection;
}
By setting the SelectedItem instead of fiddling with the indices, the correct values shall be displayed.
Concerning your question whether this logic may be better suited in an event handler or in the setter depends on your requirements. If all you need is the index, the event SelectedIndexChanged may work out for you, but if the value is needed in several places and methods that are not called by the event handler, the presented solution may be more viable.
Edit
You were correct, it has got nothing to do with the usage of SelectedIndex and SelectedItem. The issue is a bit more subtle.
I build a quick proof-of-concept and found the following:
Assuming SelectedDirection is "Right" (and the index is set accordingly)
When Directions is set, the SelectedItem on the picker seems to be reset
SelectedDirection is set to null
this.Directions.Contains(value) evaluates to false, hence _selectedDirection is not set (this hold true for SelectedDirectionIndex, since the value -1 is filtered by if(!value < 0 || value >= this.Directions.Count))
When SelectedDirection is set afterwards, the value is still "Right", hence OnPropertyChanged is not called (since the values are the same) and the SelectedItem is not set
This way there is a mismatch between the value the Picker actually holds and the property in the viewmodel, which leads to unexpected behavior.
How to mitigate the issue?
I'd still stick with the code without the indices (unless you really need them) and use the string values.
There are other possibilities, but I'd change the setter of SelectedDirection. When you allowed the value to be set to null, PropertyChanged will be raised properly when the value is set to Right afterwards. If you really need to filter what the value is set to, you should still raise OnPropertyChanged, to inform the Picker that the value has changed (preventing a mismatch between the actual Pickers value and the viewmodel)
public string SelectedDirection
{
get => _selectedDirection;
set
{
if (_selectedDirection != value)
{
if(Directions.Contains(value))
{
_selectedDirection = value;
}
else
{
_selectedDirection = DirectionTypes.Right.ToString();
}
OnPropertyChanged();
}
}
}
Found a somewhat hacky fix for this, and it seems to be a Xamarin issue. I have made the following changes to my code"
The relevant changes are in the setter for SelectedFrame:
public string SelectedFrame
{
get { return _selectedFrame; }
set
{
if (_selectedFrame != value)
{
_selectedFrame = value;
if (EnumUtils.ToEnumFromString<FrameType>(_selectedFrame) == FrameType.Road)
{
Directions = DirectionsRoad;
if (Directions.Contains(SelectedDirection))
{
/*Relevant edits*/
var position = Directions.IndexOf(SelectedDirection);
SelectedDirection = Directions[Directions.Count - position -1];
SelectedDirection = Directions[position];
}
else
{
SelectedDirectionIndex = Directions.IndexOf(DirectionType.Right.ToString());
}
}else if (EnumUtils.ToEnumFromString<FrameType>(_selectedFrame) == FrameType.Lane)
{
Directions = DirectionsAll;
/*Relevant edits*/
var position = Directions.IndexOf(SelectedDirection);
SelectedDirection = Directions[Directions.Count - position -1];
SelectedDirection = Directions[position];
}
OnPropertyChanged();
}
}
}
}
It seems that my issue arises when I change the contents of my ObservableCollectoin but the SelectedDirection stays the same.
When I change Directions (which is an ObservableCollection) by assigning it to DirectionsAll (also an ObservableCollection), I need to make sure that the SelectedDirection changes,. The added code ensures that a change actually occurs to SelectionDirection and that fixes it. Seems somewhat hacky but it works.
Outcome:
So having a play with PRISM and I have a grid who's Visibility property is bound to a property in a view model like so.
Xaml
Grid Grid.RowSpan="2" Grid.ColumnSpan="3" Background="#7F808080" Visibility="{Binding LoadingVisibility}">
Code Behind
private Visibility loadingVisibility = Visibility.Visible;
public Visibility LoadingVisibility
{
get
{
return loadingVisibility;
}
set
{
SetProperty(ref loadingVisibility, value);
}
}
Now if I do this LoadingVisibility = Visibility.Collapsed;, the grid does not disappear and is still visible.
If I then set a breakpoint at SetProperty(ref loadingVisibility, value); I can see the original value of loadingVisibility, which is set as Visibile, and I can see that value is set to Collapsed.
If I then step on I can see loadingVisiblity has now changed to collapsed as it should. At this point I expect the Grid to be notified which in turn executes 'Get' to retrieve the value. This does not occur.
The binding is working because the Get is called when loading up and if I change private Visibility loadingVisibility = Visibility.Visible; to Collapsed and run the code the grid starts invisible.
So my question is, after SetProperty is executed, why is the Get not?
EDIT:
Just so you can see where I set the property.
public ShellViewModel(IEventAggregator IEventAggregator)
{
IEventAggregator.GetEvent<PubSubEvent<HardwareLoaded>>().Subscribe(x =>
{
if (!x.HardwareOK)
{
MessageBox.Show("There was an issue loading hardware. See Log");
}
LoadingVisibility = Visibility.Collapsed;
});
}
EDIT 2:
Just found something interesting, if I comment out LoadingVisibility = Visibility.Collapsed; in the Subscribe and then add a button to the xaml and have the click event like so then everything works fine.
private void Button_Click(object sender, RoutedEventArgs e)
{
mvm.LoadingVisibility = Visibility.Collapsed;
}
So now I guess the question is why, when both methods call the set property, does only one fully work and cause the Get to work?
Quite often when using the EventAggregator, you're working on the UI thread. But seeing the HardwareLoaded type it came to me that you might be doing some checking on another thread. And as we know, bindings have to be updated from the UI thread. Normally you would use Dispather.BeginInvoke, but Prism's EventAggregator has an overload in the Subscribe method to tell the handler to offload to the UI thread.
IEventAggregator.GetEvent<PubSubEvent<HardwareLoaded>>().Subscribe(x =>
{
if (!x.HardwareOK)
{
MessageBox.Show("There was an issue loading hardware. See Log");
}
LoadingVisibility = Visibility.Collapsed;
}, ThreadOption.UIThread);
My DataGrid is defined in XAML:
<datagrid:ThemedDataGrid AutoGenerateColumns="False" ItemsSource="{Binding Model.ItemCollection, UpdateSourceTrigger=PropertyChanged}"
SelectionUnit="FullRow" SelectedItem="{Binding Model.DatagridSelectedItem, UpdateSourceTrigger=PropertyChanged}">
</datagrid:ThemedDataGrid>
I have an Event RowEditEnding where I check if in a column already exists a cell with the same value previously entered. If it exists, then I need to cancel edit. My RowEditEnding method is below:
int counter = 0;
Model.ItemCollection.ForEach(x =>
{
//if column is not empty
if (!String.IsNullOrEmpty(x.Name))
{
if (x.Name== Model.DatagridSelectedItem.Name)
{
counter++;
if (counter > 1)
{
MessageBox.Show("Doubled Name");
e.Cancel = true;
datagrid.CancelEdit(DataGridEditingUnit.Row);
}
}
}
});
The problem is this line:
datagrid.CancelEdit()
that doesn't change cell value to the previous one, and I get infinite loop. How can I solve it?
Is your collection bound to the ItemsSource property populated with custom objects? If so, I think your custom data class has to implement the IEditableObject interface.
Indeed from the DataGrid documentation:
To guarantee that edits can be committed and canceled correctly, the
objects in the DataGrid must implement the IEditableObject interface.
Try to leave out this:
datagrid.CancelEdit(DataGridEditingUnit.Row);
To my eyes, e.Cancel=true should do the job.
Implement IEditableObject Interface for your class.Which is a ObservableCollection.(Diagnostics is a class and Name is the property)
private Diagnostics backupCopy;
private bool inEdit;
public void BeginEdit()
{
if (inEdit) return;
inEdit = true;
backupCopy = this.MemberwiseClone() as Diagnostics;
}
public void CancelEdit()
{
if (!inEdit) return;
inEdit = false;
this.Name= backupCopy.Name;
}
public void EndEdit()
{
if (!inEdit) return;
inEdit = false;
backupCopy = null;
}
I had the same issue. In my personal experience, replacing datagrid.CancelEdit(DataGridEditingUnit.Row); with datagrid.EndEdit(); did the trick.
Usage Example:
In the GIF below, I have applied the method .EndEdit() to the second column (nothing is applied to the first column). As you can see, the first column allows the cell to be edited (a typing cursor appears), while the second column does not.
I've been working on an application in MVVM Light lately. I have a TextBox in my XAML bound to my UI. I'd like to validate any input and ensure that only numbers are entered. I've tried the following code:
My TextBox:
<TextBox TabIndex="1" Height="23" MinWidth="410" DockPanel.Dock="Left"
HorizontalAlignment="Left"
Text="{Binding Input, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding IsEnabled}"
AcceptsReturn="False"
local:FocusExtension.IsFocused="{Binding IsFocused}">
And in my ViewModel:
private string input;
public string Input
{
get { return this.input; }
set
{
decimal test;
if(decimal.TryParse(value, out test))
{
this.input = value;
}
else
{
this.input = "";
}
RaisePropertyChanged("Input");
}
}
This fails to update the UI. If I enter "B" and check the debugger, it runs through the setter, but fails to actually update the UI.
Curiously, if I set this.input = "TEST"; in the else block, the UI updates, but, if I attempt to set it to "", string.Empty, or the value of input before the validation, the UI fails to update.
Is this by design? Possibly a bug? Is there something I'm doing wrong?
Edit I mistakenly forgot to include RaisePropertyChanged in my example code. I've updated it. Raising it isn't the problem as I've watched the debugger run all the way through raising it and returning input via the getter.
Way you use strign type property and then convert to decimal, easier to change lik this:
public decimal Input
{
get { return this.input; }
set
{
this.input = value;
RaisePropertyChanged("Input");
}
}
And for validate use IDataErrorInfo (read more: http://blogs.msdn.com/b/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx)
What we have done is created a Custom Control, since we use it for a Currency Text Box. I warn you I have no validation that this is a good idea, or falls in line with MVVM model because all manipulation of the control are done in code behind.
In the control on the textbox we have an event on PreviewTextInput that does this
e.Handled = Functions.DoubleConverter(Convert.ToChar(e.Text), ((TextBox)sender).Text.Replace("$", ""));
Then for the function (which isnt perfect, I have a few issues with it still) is:
static public bool DoubleConverter(char c, string str)
{
if (!char.IsDigit(c))
{
if (c == '.' && (str.Contains('.')))
{
return true;
}
else if (c != '.')
{
return true;
}
}
return false;
}
Please use this as a reference, not exactly as is because it is a very crude implementation.
I have a few questions about a use of SelectMany I have encountered in one of the projects I am working on. Below is a small sample that reproduces its use (with a few Console.WriteLines I was using to help see the states at various points):
public partial class MainWindow : INotifyPropertyChanged
{
private bool _cb1, _cb2, _cb3, _isDirty;
private readonly ISubject<Unit> _cb1HasChanged = new Subject<Unit>();
private readonly ISubject<Unit> _cb2HasChanged = new Subject<Unit>();
private readonly ISubject<Unit> _cb3HasChanged = new Subject<Unit>();
private readonly ISubject<string> _initialState = new ReplaySubject<string>(1);
public MainWindow()
{
InitializeComponent();
DataContext = this;
ObserveCheckBoxes();
var initialState = string.Format("{0}{1}{2}", CB1, CB2, CB3);
_initialState.OnNext(initialState);
Console.WriteLine("INITIAL STATE: " + initialState);
}
public bool CB1
{
get
{
return _cb1;
}
set
{
_cb1 = value;
_cb1HasChanged.OnNext(Unit.Default);
}
}
public bool CB2
{
get
{
return _cb2;
}
set
{
_cb2 = value;
_cb2HasChanged.OnNext(Unit.Default);
}
}
public bool CB3
{
get
{
return _cb3;
}
set
{
_cb3 = value;
_cb3HasChanged.OnNext(Unit.Default);
}
}
public bool IsDirty
{
get
{
return _isDirty;
}
set
{
_isDirty = value;
OnPropertyChanged("IsDirty");
}
}
private void ObserveCheckBoxes()
{
var checkBoxChanges = new[]
{
_cb1HasChanged,
_cb2HasChanged,
_cb3HasChanged
}
.Merge();
var isDirty = _initialState.SelectMany(initialState => checkBoxChanges
.Select(_ => GetNewState(initialState))
.Select(updatedState => initialState != updatedState)
.StartWith(false)
.TakeUntil(_initialState.Skip(1)));
isDirty.Subscribe(d => IsDirty = d);
}
private string GetNewState(string initialState = null)
{
string update = string.Format("{0}{1}{2}", CB1, CB2, CB3);
if (initialState != null)
{
Console.WriteLine("CREATING UPDATE: " + update + " INITIAL STATE: " + initialState);
}
else
{
Console.WriteLine("CREATING UPDATE: " + update);
}
return update;
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
var newState = GetNewState();
_initialState.OnNext(newState);
Console.WriteLine("SAVED AS: " + newState);
}
}
and the xaml:
<Window x:Class="WpfSB2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<CheckBox IsChecked="{Binding CB1}"></CheckBox>
<CheckBox IsChecked="{Binding CB2}"></CheckBox>
<CheckBox IsChecked="{Binding CB3}"></CheckBox>
<Button IsEnabled="{Binding IsDirty}" Click="Button_Click">APPLY</Button>
</StackPanel>
</Grid>
</Window>
So what this little app does is show three checkboxes (all initially unchecked) and an "Apply" button. When the state of the checkboxes changes, the button should become enabled and when clicked become disabled until the state of the checkboxes changes again. If you change the state of the checkboxes but then change it back to its inital state, the button will enable/disable appropriately. The app works as expected, I am just trying to figure out why/how.
Now the questions:
Will the SelectMany call be triggered whenever the _initialState or a check box change occurs?
The first call of _initialState.OnNext(initialState); (in the constructor) doesn't really do anything when it comes to the SelectMany code. I see it makes its way to the SelectMany code but nothing is actually done (I mean, if I put a breakpoint on the checkBoxChanges.Select section it breaks but nothing is actually selected). Is this because no changes have occured to any of the checkboxes yet?
As expected, checking any checkBox triggers the isDirty check. What exactly is happening in this SelectMany statement the first time I change a single checkbox?
After checking a box, the Apply button becomse enabled and I hit Apply. This causes _initialState.OnNext(newState); to be called. Similar to my first question, nothing seems to happen in the SelectMany statement. I thought with the initial state getting a new value something would get recalculated but it seems to go straight to the OnNext handler of isDirty.Subscribe(d => IsDirty = d);
Now that I hit Apply, _initialState.OnNext has been called twice in total. If I check a new checkbox, how does the SelectMany handle that? Does it go through all of the past states of _initialState? Are those values stored until the observable is disposed?
What are the StartsWith/TakeUntil/Skip lines doing? I noticed that if I remove the TakeUntil line, the app stops working correctly as the SelectMany clause starts going through all the past values of _initialState and gets confused as to which is the actual current state to compare to.
Please let me know if you need additional info.
I think the key part of your problem is your understanding of SelectMany. I think it is easier to understand if you refer to SelectMany as "From one, select many".
For each value from a source sequence, SelectMany will provide zero, one, or many values from another sequence.
In your case you have the source sequence that is _initialState. Each time a value is produced from that sequence it will subscribe to the "inner sequence" provided.
To directly answer your questions:
1) When _initialState pushes a value, then the value will be passed to the SelectMany operator and will subscribe to the provided "inner sequence".
2) The fist call is putting the InitialState in the ReplaySubject's buffer. This means when you first subscribe to the _initialState sequence it will push a value immediately. Putting your break point in the GetNewState will show you this working.
3) When you check a check box, it will call the setter, which will OnNext the _cbXHasChanged subject (yuck), which will flow into the Merged sequence (checkBoxChanges) and then flow into the SelectMany delegate query.
4) Nothing will happen until the check boxes push new values (they are not replaysubjects)
5-6) Yes you have called it twice so it will run the selectMany delegate twice, but the TakeUntil will terminate the first "inner sequence" when the second "inner sequence" is kicked off.
This is all covered in detail on (my site) IntroToRx.com in the SelectMany chapter.