<RichTextBox x:Name="OrigText" Margin="0,0,8,0" d:LayoutOverrides="Width"/>
<Button x:Name="OrigFileBrowse" Command="{Binding BrowseCommand}" CommandParameter="{Binding ElementName=OrigText, Path=Document}" HorizontalAlignment="Center" Margin="0,0,8,2.442" Width="75" Content="Browse" Grid.Row="1" d:LayoutOverrides="Height"/>
<RichTextBox x:Name="ModifiedText" Grid.Column="1" Margin="8,0,0,0"/>
<Button x:Name="ModifiedFileBrowse" Command="{Binding BrowseCommand}" CommandParameter="{Binding ElementName=ModifiedText, Path=Document}" HorizontalAlignment="Center" Width="75" Content="Browse" Grid.Row="1" Grid.Column="1" Margin="0,0,0,2.442" d:LayoutOverrides="Height"/>
<Button x:Name="Compare" Command="{Binding CompareCommand}" HorizontalAlignment="Center" VerticalAlignment="Top" Width="75" Content="Compare" Grid.Row="2" Grid.ColumnSpan="2">
<Button.CommandParameter>
<x:Array Type="RichTextBox">
<local:CompareTextView/>
</x:Array>
</Button.CommandParameter>
</Button>
Trying to get 2 items to be passed when the Compare button is clicked as it will then execute a compare command. Attempted to make use of MultiBinding however that is firing on instantiation and therefore the converter then fires accordingly. It does NOT fire when I click compare and the compare command is executed.
With that not working, I am attempting to now reference the controls within XAML to pass within an ArrayExtension. Not sure of the syntax or if it is even possible as I know you cannot bind within the ArrayExtension. The above fails since it can not construct a new CompareTextView view, which has no default constructor since I am making use of Prism…
Pretty frustrating, hopefully someone can help me out…
EDIT:
Want to clear some things up. The issue is not that I want CanExecute called again. The issue is that at instantiation of the controls, the converter is called and executed and the values are returned…but where they go I have no clue? The converter is never called again. If I could get the initial references to the FlowDocument this would all be a moot point…but it doesn’t return things anywhere per se…since this is a command…if that makes sense…when making use of MultiBinding.
<Button x:Name="Compare" Command="{Binding CompareCommand}" HorizontalAlignment="Center" VerticalAlignment="Top" Width="75" Content="Compare" Grid.Row="2" Grid.ColumnSpan="2">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource FlowDocumentConverter}">
<Binding ElementName="OrigText" Path="Document"/>
<Binding ElementName="ModifiedText" Path="Document"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
UPDATE:
Tried what refereejoe mentions here, scroll down a little bit to see his posting. While CanExecute continually fires, this does nothing to resolve the issue. In addition I switched the MultiBinding to be a single item, it is coming back null. Again when the converter fires on instantiation the FlowDocument references are there…
ANSWER:
Abe’s mention that it was being cached led me to try something else. Since I knew that the FlowDocument references were available when the converter was called I knew they were there. Something was getting fouled up. The key piece appears to be in the converter itself. I was simply returning the object[]. Then when the command fired the arg was indeed an object[] but the two items were null. I created a class called Docs, which had two properties, one for each FlowDocument reference. When the converter fired I set the properties appropriately and then returned the Docs object. Now when I initiated the compare command, the Docs object was the args and it had the reference to the FlowDocuments just as I needed! Not sure if this is by design, but the fact that the items get lost when using the object[] doesn’t make sense to me.
The proper way to do this is indeed with a
MultiBindingon theCommandParameter. You won’t see it call yourCanExecutemethod unless WPF is informed that the method could return a different value than it had already cached (via theCanExecuteChangedevent).Since you are relying on the parameter passed in to determine this, we have to raise the event when the parameter changes. Since we can’t really determine that in the command, we can use another technique: tell WPF to poll our command anytime it polls
UICommands. This is done by implementing yourICommandlike so:Obviously, this prevents you from using the Prism
DelegateCommand, but this will respond to changes in the command parameters.UPDATE
Another thing to consider is that the
Documentproperty on theRichTextBoxisn’t actually changing. Instead, when you type into it, the content of theFlowDocumentchanges. Since the property instances don’t change, the converter won’t get fired again, and the originally converted value will get stored in theCommandParameterproperty.One of the ways to force the converter to be called again is to add a
Bindingto theMultiBindingthat is bound to a property that will change every time the text of theRichTextBoxchanges.A somewhat hacky solution would be to use the
IsKeyboardFocusWithinproperty, as that will mimic the default binding behavior ofTextBox.Text(i.e. when theTextBoxloses focus, theBindingupdates):Obviously, in your converter, you will need to ignore these additional values, as they aren’t relevant to your conversion.