x:Array中的XAML引用控件和属性

时间:2010-09-07 17:14:27

标签: wpf xaml binding

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

单击“比较”按钮时,尝试获取2个项目,然后执行比较命令。尝试使用MultiBinding但是在实例化时触发,因此转换器然后相应地触发。单击compare并执行compare命令时,它不会触发。

由于这不起作用,我现在尝试引用XAML中的控件以在ArrayExtension中传递。不确定语法或者是否可能,因为我知道你无法在ArrayExtension中绑定。上面的失败是因为它无法构造一个新的CompareTextView视图,因为我正在使用Prism ......所以没有默认的构造函数...

非常令人沮丧,希望有人可以帮助我...

修改

想清除一些事情。问题不在于我想再次调用CanExecute。问题在于,在实例化控件时,转换器被调用并执行并返回值......但是在他们去的地方我没有线索?永远不会再次调用转换器。如果我可以获得对FlowDocument的初始引用,这将是一个没有实际意义的点...但它本身并不返回任何东西...因为这是一个命令...如果这是有意义的...制作时使用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>

更新:

尝试了什么裁判提到here,向下滚动一下,看看他的帖子。虽然CanExecute不断触发,但这无法解决问题。另外我将MultiBinding切换为单个项目,它将返回null。再次当转换器在实例化时触发时,FlowDocument引用就在那里......

解答:

安倍提到它被缓存导致我尝试别的东西。因为我知道在调用转换器时FlowDocument引用是可用的,所以我知道它们在那里。有些东西被搞砸了。关键部分似乎在转换器本身。我只是返回对象[]。然后当命令触发时,arg确实是一个对象[]但是这两个项目都是null。我创建了一个名为Docs的类,它有两个属性,每个属性对应一个FlowDocument引用。当转换器触发时,我适当地设置了属性,然后返回Docs对象。现在当我启动compare命令时,Docs对象就是args,它就像我需要的那样引用了FlowDocuments!不确定这是否是设计的,但是在使用对象[]时项目丢失的事实对我来说没有意义。

1 个答案:

答案 0 :(得分:2)

执行此操作的正确方法确实是MultiBinding上的CommandParameter。您不会看到它调用您的CanExecute方法,除非WPF被告知该方法可以返回与已缓存的值不同的值(通过CanExecuteChanged事件)。

由于您依赖传入的参数来确定这一点,因此我们必须在参数更改时引发事件。由于我们无法在命令中真正确定,我们可以使用另一种技术:告诉WPF在轮询UICommands时随时轮询我们的命令。这是通过实施您的ICommand来实现的:

public class MyCommand : ICommand
{
    public void Execute(object parameter) { /* do stuff */ }
    public bool CanExecute(object parameter { /* determine if we can do stuff */ }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

显然,这会阻止您使用Prism DelegateCommand,但这会响应命令参数的更改。

<强>更新

要考虑的另一件事是Document上的RichTextBox属性实际上并没有改变。相反,当您键入时,FlowDocument的内容会发生变化。由于属性实例不会更改,因此转换器不会再次触发,并且最初转换的值将存储在CommandParameter属性中。

强制转换器再次被调用的一种方法是向Binding添加一个MultiBinding,该RichTextBox绑定到每次更改的属性IsKeyboardFocusWithin更改的文字。

一个有点hacky的解决方案是使用TextBox.Text属性,因为它会模仿TextBox的默认绑定行为(即当Binding失去焦点时,{{1}更新):

<MultiBinding Converter="{StaticResource FlowDocumentConverter}">
    <Binding ElementName="OrigText" Path="Document" />
    <Binding ElementName="ModifiedText" Path="Document" />
    <Binding ElementName="OrigText" Path="IsKeyboardFocusWithin" />
    <Binding ElementName="ModifiedText" Path="IsKeyboardFocusWithin" />
</MultiBinding>

显然,在您的转换器中,您需要忽略这些附加值,因为它们与您的转换无关。