ContentControl在两个按钮之间切换

时间:2015-06-06 16:31:09

标签: c# wpf

我整晚都在敲打这个。我想做的就是有一个内容控件,可以根据ViewModel中的布尔值在显示两个不同的按钮之间切换。

基本上我有一个任务在后台运行,带有取消按钮。一旦你点击取消并且任务停止,取消按钮应该变为后退按钮。这是两个单独的按钮元素,而不仅仅是更改单个按钮的属性。我正在使用MahApps TransitioningContentControl,所以我希望能够使用转换。

如果在XAML中大部分都可以完成,我会很高兴。我真的不想为一些简单的东西添加一堆样板代码。

编辑:这是代码片段。没有多少,因为我刚刚删除了所有无效的内容。

<Controls:TransitioningContentControl x:Name="CancelBackButtonControl" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Height="80">
    <Canvas>
        <Button x:Name="CancelButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Style="{DynamicResource MetroCircleButtonStyle}" Height="80" IsCancel="True" Content="{StaticResource appbar_close}" BorderBrush="Black" Command="{Binding CancelCommand}"/>
        <Button x:Name="GoBackButton" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80" Style="{DynamicResource MetroCircleButtonStyle}" Height="80" IsCancel="True" Content="{StaticResource appbar_arrow_left}" BorderBrush="Black" Command="{Binding GoBackCommand}"/>
    </Canvas>
</Controls:TransitioningContentControl>

3 个答案:

答案 0 :(得分:5)

有很多方法可以实现这一目标(这就是WPF的美妙之处);但是,在我个人看来,如果你只是使用一个来自ToggleButton的控件,例如RadioButton,那么你的工作就会更少“,特别是因为你希望它完成所有在XAML中。重要的是不要通过视觉效果来考虑任何控件,而应考虑它们的功能。我之前用RadioButton完成了一些令人难以置信的事情,所以这是我要展示的第一件事;但是,常规按钮方法包含在本答复的后半部分中。

以下是两种方法(RadioButtonButton)的完整示例,完全在XAML中完成:

预览

enter image description here

<强>代码:

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="{x:Type RadioButton}" x:Key="FlatRadioButtonStyle">
            <Setter Property="Width" Value="100"/>
            <Setter Property="Background" Value="#FF346FD6"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Padding" Value="5,2,5,3"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RadioButton}">
                        <Border Background="{TemplateBinding Background}"
                                Width="{TemplateBinding Width}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                VerticalAlignment="{TemplateBinding VerticalAlignment}"
                                HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
                            <ContentPresenter Content="{TemplateBinding Content}"
                                              Margin="{TemplateBinding Padding}"
                                              HorizontalAlignment="Center"
                                              VerticalAlignment="Center"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="#FF6696E9"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter Property="Visibility" Value="Collapsed"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid>
        <RadioButton x:Name="BackButton" Content="Back">
            <RadioButton.Style>
                <Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource FlatRadioButtonStyle}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=CancelButton}" Value="True">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </RadioButton.Style>
        </RadioButton>
        <RadioButton x:Name="CancelButton" Content="Cancel" IsChecked="True">
            <RadioButton.Style>
                <Style TargetType="{x:Type RadioButton}" BasedOn="{StaticResource FlatRadioButtonStyle}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsChecked, ElementName=BackButton}" Value="True">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </RadioButton.Style>
        </RadioButton>
    </Grid>
</Window>

大多数资源样式代码都是视觉样式和模板,专注于使单选按钮看起来像常规按钮,因此它并不重要。我们将关注的领域是Triggers。您会注意到,在资源样式中,我确保在检查RadioButton时它会崩溃。但是,在每个按钮的本地样式中,我确保在检查其他RadioButton时,它会使当前RadioButton可见。这必须以本地风格完成,因为我们需要将ElementName传递给Binding。因此,当RadioButton被检查时,它会折叠并使另一个RadioButton可见。你还会注意到我默认选中了我想要隐藏的按钮。显然,你可以用绑定来连接它。

类似的方法可以应用于常规按钮:

预览

enter image description here

<强>代码:

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">   
    <Window.Resources>
        <Style TargetType="{x:Type Button}" x:Key="ToggleButtonStyle">
            <Setter Property="Width" Value="100"/>
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Visibility" Value="Collapsed"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Button x:Name="CancelButton" Content="Cancel">
            <Button.Style>
                <Style TargetType="{x:Type Button}" BasedOn="{StaticResource ToggleButtonStyle}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsFocused, ElementName=BackButton}" Value="True">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
        <Button x:Name="BackButton" Content="Back">
            <Button.Style>
                <Style TargetType="{x:Type Button}" BasedOn="{StaticResource ToggleButtonStyle}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsFocused, ElementName=CancelButton}" Value="True">
                            <Setter Property="Visibility" Value="Visible"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</Window>

此处,我正在与IsChecked合作,而不是IsFocused。您可以通过使用EventTriggerClick事件来完成类似的事情......但是,还有更多工作要做。 IsPressed可能看起来像是一个很好的候选人,但问题是,一旦按下按钮,另一个几乎会瞬间出现,并且IsPressed几乎会立即设置为true 。所以,你最终会发现这种循环行为,似乎没有任何事情发生。请注意,我使用Grid将这些按钮放在彼此的顶部,默认情况下我希望在顶部显示这个按钮,这样我就不必担心默认的可见性或焦点。但是,您可以使用任何其他面板,只需将您要隐藏的按钮的Visibility默认设置为Collapsed

如果您不想使用多个控件(在这种情况下为两个按钮),您还可以根据Content的条件设置按钮的DataTrigger属性以显示不同的文本。您只需确保正确处理Command

答案 1 :(得分:3)

由于您要求仅使用XAML方法在基于ViewModel属性的内容控件中切换按钮,具体如何:

首先定义按钮样式以将两个按钮路由到同一事件:

<Style x:Key="buttonClickButton" TargetType="Button">
    <EventSetter Event="Click"  Handler="Button_Click"/>
</Style>

然后使用数据触发器定义内容控件样式,根据名为“IsCancelButton”(bool)的ViewModel属性切换内容:

<Style x:Key="ButtonSwitchContentCtrl" TargetType="ContentControl">
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsCancelButton}" Value="True">
            <Setter Property="Content">
                <Setter.Value>
                    <Button x:Name="CancelButton" Style="{StaticResource buttonClickButton}" 
                            HorizontalAlignment="Left" VerticalAlignment="Top" 
                            Width="80"  Height="80" IsCancel="True" Content="Cancel Button" BorderBrush="Black" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
        <DataTrigger Binding="{Binding IsCancelButton}" Value="False">
            <Setter Property="Content">
                <Setter.Value>
                    <Button x:Name="GoBackButton" Style="{StaticResource buttonClickButton}" 
                            HorizontalAlignment="Left" VerticalAlignment="Top" 
                            Width="80"  Height="80" IsCancel="True" Content="Go Back Button" BorderBrush="Black" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

然后让你的按钮显示如下:

<ContentControl Style="{StaticResource ButtonSwitchContentCtrl}"/>

答案 2 :(得分:1)

您可以使用一个Button(例如在XAML中声明为Name="btnCancel")和使用Lambda样式事件订阅的C#代码隐藏中的简单代码片段来实现此类功能,如:

    btnCancel.Click+=(s,e)=>{
    if (btnCancel.Text=="Cancel")
    {
      // SOME CODE CORRESPONDING TO "CANCEL" CLICK EVENT
      btnCancel.Text ="GoBack"
    }
    else 
    {
      // CORRESPONDING TO "GoBack" CLICK EVENT
      btnCancel.Text ="Cancel"
    }
}

如果您想在Button上使用某些图形内容(图像),请使用该Button的Tag属性而不是Text,并以编程方式在图像之间切换。

结合其他注意事项:您所描述的业务逻辑可以使用DataTriggers在XAML中实现(正如其他人所做的那样),但不是为2-Buttons解决方案编写大量的XAML,而是实现一个单按钮解决方案,可以像这样,也可以使用.NET ToggleButton Class(re:https://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.togglebutton%28v=vs.110%29.aspx);另外,它可能是一个CheckBox控件,只是风格正确。

无论如何,除了改变Button的可视状态之外,你很可能还需要事件处理程序来完成一些实际的工作,这样紧凑的Lambda风格的事件订阅会很方便。

希望这可能会有所帮助。最好的问候,