C# 如何使用ToggleButton更改ListBoxItem中的命令
我想使用C# 如何使用ToggleButton更改ListBoxItem中的命令,c#,wpf,xaml,C#,Wpf,Xaml,我想使用切换按钮(DevMode)更改命令,例如: 如果IsChecked为true执行命令(1) 如果IsChecked为false执行命令(2) 这是我的密码: <DockPanel> <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> <ToggleButton x:Name="DevMode" Horizonta
切换按钮(DevMode
)更改命令,例如:
- 如果
IsChecked
为true
执行命令(1)
- 如果
IsChecked
为false
执行命令(2)
这是我的密码:
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<ToggleButton x:Name="DevMode" HorizontalAlignment="Right" Width="120" Height="30" Content="Developer Mode"/>
</StackPanel>
<ListBox DockPanel.Dock="Bottom" ItemsSource="{Binding Tiles}" SelectedItem="{Binding SelectedTile}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Width="600" Height="600" RenderTransformOrigin="0.5, 0.5"
Rows="{Binding Path=GetRows}"
Columns="{Binding Path=GetCols}">
</UniformGrid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=ImagePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction
<!--the command which I need to change-->
Command="{Binding DataContext.Command1, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding DataContext.SelectedTile, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
Command=“{Binding DataContext.Command1,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBox}}”
CommandParameter=“{Binding DataContext.SelectedFile,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBox}}”/
您可以将ToggleButton
的IsChecked
属性绑定到视图模型,但在视图模型的上下文中,可能会给它一个比IsChecked
更有意义的名称
<ToggleButton x:Name="DevMode" HorizontalAlignment="Right" Width="120" Height="30" Content="Developer Mode" IsChecked="{Binding IsChecked}"/>
在视图模型中,可以根据IsChecked
状态决定执行哪种方法。如果您有一个can-execute委托,您也应该调整它
private bool CanExecuteMyCommand(object item)
{
return IsChecked && Command1.CanExecute(item) || !IsChecked && Command2.CanExecute(item);
}
private void ExecuteMyCommand(object item)
{
if (IsChecked && Command1.CanExecute(item))
Command1.Execute(item);
else if (!IsChecked && Command2.CanExecute(item))
Command2.Execute(item);
}
请注意,代码假定您也在其他地方重用Command1
和Command2
。如果没有,您可以删除它们,只需使用它们的Execute
和CanExecute
委托即可。在不破坏MVVM的情况下执行此操作的最佳方法是使用带有如下数据触发器的样式:
<ListBox DockPanel.Dock="Bottom" ItemsSource="{Binding Tiles}" SelectedItem="{Binding SelectedTile}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Width="600" Height="600" RenderTransformOrigin="0.5, 0.5" Rows="{Binding Path=GetRows}" Columns="{Binding Path=GetCols}">
</UniformGrid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Path=ImagePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding CommandB}"/>
<!--Your other command-->
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=DevMode, Path=IsCecked}" Value="True">
<!--Your trigger linked to the btn-->
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Path=ImagePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding CommandA}"/>
<!--Your command-->
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
您可以将切换按钮状态传递到视图模型中,并决定在其中运行哪个命令。非常感谢,此解决方案非常有用!在我的选项中,您应该仅在gui中执行此操作,而不是在viewmodel中执行此操作,但是我同意这是一个优势case@DenisSchaf由于这种方法符合MVVM,使用其中一种取决于实际需求或个人偏好。您真的需要两个数据触发器吗?虽然您可能会争辩说,IsChecked
是一个可为空的bool,但在单个DataTrigger中应该有一个由样式设置器设置的“默认”ItemTemplate和一个由设置器设置的ItemTemplate。我在这里看到的一个问题是,根据IsChecked
属性重置DataTemplate
中的整个Trigges
集合。如果您有多个触发器,甚至可能依赖于另一个属性,此解决方案可能会快速升级。@您可以轻松更改上面的示例,仅更改命令以避免重复应用。但是我没有这样做,因为我不使用eventtrigger东西,因为我认为它们破坏了MVVM想法的一部分……有点……有时……不知何故……也许。。所以我无法测试它,决定更改整个模板。我同意你的建议和这个建议一样有效,但是这个建议使视图和模型彼此之间保持了更大的距离。当使用普通绑定而不是交互触发器时,可以很容易地在图像内部移动样式。我想在这种情况下,你可以通过把图像放在一个按钮里,很容易地避免交互触发。交互触发器始终是一种变通方法,它为控件提供了一个从未被认为可以提供的功能,就像在本例中将图像转换为按钮一样,而正确的方法是将图像放入按钮中
<ListBox DockPanel.Dock="Bottom" ItemsSource="{Binding Tiles}" SelectedItem="{Binding SelectedTile}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Width="600" Height="600" RenderTransformOrigin="0.5, 0.5" Rows="{Binding Path=GetRows}" Columns="{Binding Path=GetCols}">
</UniformGrid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Style>
<Style TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Path=ImagePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding CommandB}"/>
<!--Your other command-->
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=DevMode, Path=IsCecked}" Value="True">
<!--Your trigger linked to the btn-->
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Path=ImagePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding CommandA}"/>
<!--Your command-->
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>