我创建了两个用户控件,一个在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控件的方法/命令?
答案 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适用于不同的使用方法,您只需找到适合您/您的应用程序的方法。