問題描述:MVVMLight框架中,改寫ListBox、ListBox.ItemTemplate模板時,模板裡面的Button/Image控制元件繫結命令後,觸發不起作用,但在ListBox外的命令正常繫結到指定的ViewModel;
VieweModel 為CarPicturesViewModel,繫結上下文DataContext="{Binding CarPicturesVM ,Source={StaticResource Locator}}"
問題程式碼:
1.宣告繫結資料類CarInfo
public class CarInfo : BaseNotifyProperty { private int carIndex; public int CarIndex { get { return carIndex; } set { carIndex = value; OnPropertyChanged("CarIndex"); } } private string carName; public string CarName { get { return carName; } set { carName = value; OnPropertyChanged("CarName"); } } }
2.介面設計程式碼,整個介面是UserControl
<UserControl x:Class="CarRental.View.CarPicturesView" DataContext="{Binding CarPicturesVM ,Source={StaticResource Locator}}"> <Grid> <ListBox x:Name="listboxImages" HorizontalAlignment="Left" VerticalAlignment="Top" Width="1780" Height="870" ItemsSource="{Binding DisplayImageList}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Background="Transparent"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate x:Name="gridDataTemplate"> <Border x:Name="DataTemplateBr" CornerRadius="5" HorizontalAlignment="Left" BorderThickness="2" VerticalAlignment="Top"> <Border.Background> <ImageBrush ImageSource="Pack://application:,,,/CarRental;component/Images/CarInfo/white.png" Opacity="0.32"> </ImageBrush> </Border.Background> <Grid Margin="5" Height="400" Width="250"> <Button Command="{Binding AddImageRecord}" /> <Grid Visibility="{Binding IsShowAddImage,Converter={StaticResource boolToNVisibilityConverter}}"> <Grid.RowDefinitions> <RowDefinition Height="250"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Image x:Name="image_Check" Grid.Row="0" Margin="5" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Panel.ZIndex="9999" > <Image.Style> <Style TargetType="{x:Type Image}"> <Setter Property="Source" Value="Pack://application:,,,/CarRental;component/Images/CarInfo/check.png"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Source" Value="/CarRental;component/Images/CarInfo/check_sel.png"/> </Trigger> </Style.Triggers> </Style> </Image.Style> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseDown"> <i:InvokeCommandAction Command="{Binding AddRentalRecord}"/> </i:EventTrigger> </i:Interaction.Triggers> </Image> <StackPanel Margin="0,5,0,0" Grid.Row="1"> <Grid> <TextBlock Margin="0,5,0,0" Text="名稱:" Style="{StaticResource txtblock}"/> <TextBlock Margin="45,5,0,0" Text="{Binding CarName}" Style="{StaticResource txtblock}" Width="200"/> </Grid> </StackPanel> </Grid> </Grid> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </UserControl>
問題原因:因為 ListBox 的ItemsSource繫結了 DisplayImageList,DisplayImageList 是一個 CarInfo 類的列表,ListBox裡面控制元件的DataContext就成了CarInfo也就是裡面控制元件的Binding都是CarInfo的屬性,比如名稱(Binding="{Binding Name}")。而CarInfo裡沒有AddImageRecord,所以就不能觸發操作了。
解決方法:把Button的Command繫結為ViewModel裡面的AddImageRecord就好了,而ListBox的DataContext就是ViewModel,那這樣做就好了;
解決程式碼: <Button Command="{Binding CarPicturesVM.AddRentalRecord,Source={StaticResource Locator}}" /> 或者
Command="{Binding DataContext.AddRentalRecord,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 或者
Command="{Binding DataContext.AddRentalRecord,RelativeSource={RelativeSource AncestorLevel=2, AncestorType={x:Type UserControl}}}"
AncestorLevel:模式中獲取或設定要查詢的上級節點的級別。 使用 1 表示與繫結目標元素最近的一個級別。
返回值:上級節點級別。 使用 1 表示與繫結目標元素最近的一個級別。
AncestorType:獲取或設定要查詢的上級節點的型別。
修改後正確程式碼
<UserControl x:Class="CarRental.View.CarPicturesView" DataContext="{Binding CarPicturesVM ,Source={StaticResource Locator}}"> <Grid> <ListBox x:Name="listboxImages" HorizontalAlignment="Left" VerticalAlignment="Top" Width="1780" Height="870" ItemsSource="{Binding DisplayImageList}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top" Background="Transparent"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate x:Name="gridDataTemplate"> <Border x:Name="DataTemplateBr" CornerRadius="5" HorizontalAlignment="Left" BorderThickness="2" VerticalAlignment="Top"> <Border.Background> <ImageBrush ImageSource="Pack://application:,,,/CarRental;component/Images/CarInfo/white.png" Opacity="0.32"> </ImageBrush> </Border.Background> <Grid Margin="5" Height="400" Width="250"> <Button Command="{Binding DataContext.AddImageRecord,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> <Grid Visibility="{Binding IsShowAddImage,Converter={StaticResource boolToNVisibilityConverter}}"> <Grid.RowDefinitions> <RowDefinition Height="250"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Image x:Name="image_Check" Grid.Row="0" Margin="5" Height="30" Width="30" HorizontalAlignment="Left" VerticalAlignment="Top" Panel.ZIndex="9999" > <Image.Style> <Style TargetType="{x:Type Image}"> <Setter Property="Source" Value="Pack://application:,,,/CarRental;component/Images/CarInfo/check.png"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Source" Value="/CarRental;component/Images/CarInfo/check_sel.png"/> </Trigger> </Style.Triggers> </Style> </Image.Style> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseDown"> <i:InvokeCommandAction Command="{Binding DataContext.AddRentalRecord,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/> </i:EventTrigger> </i:Interaction.Triggers> </Image> <StackPanel Margin="0,5,0,0" Grid.Row="1"> <Grid> <TextBlock Margin="0,5,0,0" Text="名稱:" Style="{StaticResource txtblock}"/> <TextBlock Margin="45,5,0,0" Text="{Binding CarName}" Style="{StaticResource txtblock}" Width="200"/> </Grid> </StackPanel> </Grid> </Grid> </Border> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </UserControl>