Wpf属性绑定vs命令

时间:2014-03-31 13:58:33

标签: wpf binding command

我创建了两个用户控件,一个在Canvas上显示我的数据/视图模型集合的二维笛卡尔映射。另一个是1列可滚动图像库,它显示每个数据模型的图像。 (snippetized)地图基于:

<ItemsControl 
        ItemsSource="{Binding Defects}"
        ItemTemplateSelector="{StaticResource IconSelector}">            
        <!-- ItemsPanelTemplate -->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas x:Name="MapCanvas" Height="10000"/>                       
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <!-- ItemContainerStyle -->
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Top" Value="{Binding Y}" />
                <Setter Property="Canvas.Left" Value="{Binding X}" />                     
            </Style>               
        </ItemsControl.ItemContainerStyle>
</ItemsControl>

(再次,snippetized)图片库基于:

<ScrollViewer Name="ScrollContainer"
        Grid.Column="1" PanningMode="VerticalOnly" 
        VerticalScrollBarVisibility="Visible"
        HorizontalScrollBarVisibility="Visible"                  
        Background="White">
    <ItemsControl Name="ItemsContainer" ItemsSource="{Binding Defects}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border BorderThickness="5" BorderBrush="Gray" Margin="2">
                    <Image Source="{Binding ImageUrl}" Margin="2"></Image>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

现在我想为这两个数据视图添加一些同步。即,当点击地图上的一个图标时,我希望图库滚动到相应的图像。 我试图向两个控件添加依赖项属性以指向所选索引。这不是我想要的,因为我想要一些额外的灵活性。有时我想用动画完成滚动,有时我想要立即同步所选索引。 因此,我尝试将自定义命令BringIntoView添加到viewmodel。此命令采用bool输入来指定是否必须使用动画执行操作。我可以将datatemplate绑定到我的自定义命令,只要单击地图上的图标,地图控件就会正确调用自定义命令上的执行。

但是我被困在画廊一边,我怎么能把这个命令绑定到方法后面的一些代码,或者可能是控件上的其他一些方法呢?命令绑定不起作用,因为它不允许动态绑定命令。以下引发编译时错误,因为CommandBinding上的Command属性不是依赖项属性:

<UserControl.CommandBindings>
    <CommandBinding Command="{Binding BringIntoView}" Executed="OnBringIntoViewExecuted"/>
</UserControl.CommandBindings> 

我可以直接添加静态命令和引用,但这至少会将视图绑定到viewmodel命令。那么如何实现这种级别的命令链接,同时保持与视图的解耦?

换句话说,WPF依赖项属性系统允许绑定两个UI控件的两个UI特定属性。如何为命令/事件实现相同的目标?也就是说,来自用户控件的UI事件/命令连接到另一个UI控件的方法/命令?

1 个答案:

答案 0 :(得分:0)

我找到了解决此设计问题的方法。与依赖属性发生的情况类似,自定义控件也可以公开自定义命令。由于控件直接暴露的命令(与viewmodel公开的命令相反)是特定于UI的,因此最适合使用RoutedUiCommand而不是自定义ICommand实现。 RoutedUiCommands可以作为静态属性公开,就像DependencyProperty所发生的那样。在我的例子中,gallery控件公开了一个静态的BringIntoView命令:

public partial class DefectGallery {
  // the control exposes the following commands:
  public static readonly RoutedUiCommand BringIntoView = new RoutedUiCommand;
  // the control exposes the following depdendency properties:
  public static readonly DependencyProperty ScrollSpeedProperty = DependencyProperty.Register(...);   
  ... 
}  

该命令绑定到DefectGallery控件的xaml文件的代码隐藏:

<UserControl.CommandBindings>
   <CommandBinding Command="{x:static local:DefectGallery.BringIntoView}" Executed="OnBringIntoViewExecuted"/>
</UserControl.CommandBindings> 

最后,其他一些控件需要触发BringIntoViewCommand。它可以例如WPF提供了一个像按钮一样的命令源。在我的例子中,我已经在地图控件上实现了ICommandSource接口,以便允许指定在点击地图上的图标时执行的自定义命令。我现在可以使用xaml中的地图控件(上面的第一个片段),如下所示:

<MapControl 
    Command="{x:static local:DefectGallery.BringIntoView}"
    CommandTarget="{Binding ElementName=defectGalleryInstance}"
 />

因此我可以有效地呼叫&#34;来自另一个控件的控件只使用声明性xaml。

现在,这似乎是添加依赖属性的基本模式,所以我很惊讶我没有找到相关指南。对我来说,控件暴露属性和命令似乎很自然;我认为这两个是&#34;界面&#34;对其他UI组件的UI控件,而View模型绑定是面向应用程序层的界面。哦,WPF适用于不同的使用方法,您只需找到适合您/您的应用程序的方法。