动态更改按钮样式

时间:2014-10-09 10:17:04

标签: c# wpf datagrid styles

我在ResourceDictionary中定义了两种不同的样式,如下所示:

<Style TargetType="{x:Type Button}" x:Key="EditButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="Border" Background="{StaticResource BrushBlueSelector}" Padding="5,2" SnapsToDevicePixels="true" CornerRadius="3">
                    <Border.Effect>
                        <DropShadowEffect ShadowDepth="0" Color="Turquoise" BlurRadius="8" />
                    </Border.Effect>
                    <Path x:Name="buttonSymbol" Data="M0,44.439791L18.98951,54.569246 0.47998798,62.66881z M17.428029,12.359973L36.955557,23.568769 21.957478,49.686174 20.847757,46.346189 15.11851,45.756407 14.138656,42.166935 8.5292659,41.966761 6.9493899,38.037481 2.4399572,38.477377z M26.812517,0.0009765625C27.350616,-0.012230873,27.875986,0.10826397,28.348372,0.3782568L42.175028,8.3180408C43.85462,9.2780154,44.234529,11.777948,43.02482,13.89789L41.375219,16.767812 21.460039,5.3381228 23.10964,2.4582005C23.979116,0.941679,25.437378,0.034730911,26.812517,0.0009765625z" 
                          Stretch="Uniform" Fill="#FFFFFFFF" Width="24" Height="24" RenderTransformOrigin="0.5,0.5">
                        <Path.RenderTransform>
                            <TransformGroup>
                                <TransformGroup.Children>
                                    <RotateTransform Angle="0" />
                                    <ScaleTransform ScaleX="1" ScaleY="1" />
                                </TransformGroup.Children>
                            </TransformGroup>
                        </Path.RenderTransform>
                    </Path>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="{StaticResource BrushOrangeSelector}"/>
                        <Setter TargetName="Border" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="Orange" BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="{StaticResource BrushHeaderBackground}"/>
                        <Setter TargetName="Border" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="Gray" BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter TargetName="Border" Property="Background" Value="Gray"/>
                        <Setter TargetName="Border" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="Gray" BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="Tag" Value="EditButton" />
    <Setter Property="Margin" Value="3" />
    <Setter Property="Focusable" Value="False" />

</Style>

<Style TargetType="{x:Type Button}" x:Key="SaveButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="Border" Background="{StaticResource BrushBlueSelector}" Padding="5,2" SnapsToDevicePixels="true" CornerRadius="3">
                    <Border.Effect>
                        <DropShadowEffect ShadowDepth="0" Color="Turquoise" BlurRadius="2" />
                    </Border.Effect>
                    <Path x:Name="buttonSymbol" Data="M8.1099597,36.94997L8.1099597,41.793968 39.213959,41.793968 39.213959,36.94997z M12.42,0.049999889L18.4,0.049999889 18.4,12.252 12.42,12.252z M0,0L7.9001866,0 7.9001866,14.64218 39.210766,14.64218 39.210766,0 47.401001,0 47.401001,47.917 0,47.917z" 
                          Stretch="Uniform" Fill="#FFFFFFFF" Width="24" Height="24" RenderTransformOrigin="0.5,0.5">
                        <Path.RenderTransform>
                            <TransformGroup>
                                <TransformGroup.Children>
                                    <RotateTransform Angle="0" />
                                    <ScaleTransform ScaleX="1" ScaleY="1" />
                                </TransformGroup.Children>
                            </TransformGroup>
                        </Path.RenderTransform>
                    </Path>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="Green"/>
                        <Setter TargetName="Border" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="Green" BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="{StaticResource BrushHeaderBackground}"/>
                        <Setter TargetName="Border" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="Gray" BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="Tag" Value="SaveButton" />
    <Setter Property="Margin" Value="3" />
    <Setter Property="Focusable" Value="False" />

</Style>

我在dataGrid中有一个编辑按钮,如下所示:

<DataGrid Grid.Column="1" Margin="50" ItemsSource="{Binding Names}"
          CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False">

    <DataGrid.Columns>

        <DataGridTextColumn Binding="{Binding}" Width="*" Header="Names"/>

        <DataGridTemplateColumn Header="Edit">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Style="{StaticResource EditButton}" Click="EditButton_InsideDataGrid_Click" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

    </DataGrid.Columns>

</DataGrid>

这是点击事件:

private void EditButton_InsideDataGrid_Click(object sender, RoutedEventArgs e)
{
    var button = sender as Button;
    string tagValue = String.Empty;

    if (button != null)
    {
        tagValue = button.Tag.ToString();

        if (tagValue == "EditButton")
        {
            button.Style = (Style)Application.Current.Resources["SaveButton"];
        }
        else if (tagValue == "SaveButton")
        {
            button.Style = (Style)Application.Current.Resources["EditButton"];
        }
    }        
}

现在,它运作正常。我可以看到:

Initially      : Style is EditButton.
Click 1st time : Style is SaveButton.
Click 2nd time : Style is EditButton.
Click 3rd time : Style is SaveButton.
Click 4th time : Style is EditButton.
Click 5th time : Style is SaveButton.
......
......
......

现在,当我在editButton的Click事件中添加下面提到的代码时:

    int colIndex = 0;
    int rowIndex = 0;

    DependencyObject dep = (DependencyObject)e.OriginalSource;
    while (dep != null && !(dep is DataGridCell))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    if (dep == null)
        return;

    if (dep is DataGridCell)
    {

        colIndex = ((DataGridCell)dep).Column.DisplayIndex;

        while (dep != null && !(dep is DataGridRow))
        {
            dep = VisualTreeHelper.GetParent(dep);
        }

        DataGridRow row = (DataGridRow)dep;
        rowIndex = FindRowIndex(row);
    }

    while (dep != null && !(dep is DataGrid))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    if (dep == null)
        return;

    DataGrid dg = (DataGrid)dep;

    for (int column = 0; column < colIndex; column++)
    {
        if (!(dg.Columns[column].IsReadOnly))
        {
            DataGridCell cell = GetDataGridCell(new DataGridCellInfo(dg.Items[rowIndex], dg.Columns[column]));
            //cell.IsEditing = true;
        }
    }

    dg.BeginEdit();

}

public DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
{
    var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
    if (cellContent != null)
        return (DataGridCell)cellContent.Parent;

    return null;
}

private int FindRowIndex(DataGridRow row)
{
    DataGrid dataGrid = ItemsControl.ItemsControlFromItemContainer(row) as DataGrid;

    int index = dataGrid.ItemContainerGenerator.IndexFromContainer(row);

    return index;
}

现在,我的结果是:

Initially      : Style is EditButton.
Click 1st time : Style is EditButton.
Click 2nd time : Style is SaveButton.
Click 3rd time : Style is EditButton.
Click 4th time : Style is SaveButton.
Click 5th time : Style is EditButton.
......
......
......

以下是我重现同样问题的示例项目:

https://drive.google.com/file/d/0B5WyqSALui0beVJXTG5yWTZwZm8/view?usp=sharing

更新

@Yoyo建议的新样本:https://drive.google.com/file/d/0B5WyqSALui0bUGxRRklDOUpKRms/view?usp=sharing

我试图成功关注@ Yoyo的说明。但问题仍然存在。

2 个答案:

答案 0 :(得分:1)

以下是我提供解决问题的方法

我重写按钮的样式

<Style TargetType="{x:Type Button}"
       x:Key="EditSaveStyle">
    <Style.Resources>
        <Brush x:Key="BrushHeaderBackground">#FF2A2A2A</Brush>
        <Brush x:Key="BrushBlueSelector">#FF0094FF</Brush>
        <Brush x:Key="BrushOrangeSelector">#FFFF6A00</Brush>
    </Style.Resources>
    <Setter Property="Margin"
            Value="3" />
    <Setter Property="Focusable"
            Value="False" />
    <Setter Property="Width"
            Value="32" />
    <Setter Property="Height"
            Value="32" />
    <Setter Property="Background"
            Value="{StaticResource BrushOrangeSelector}" />
    <Setter Property="Content">
        <Setter.Value>
            <StreamGeometry>
                M0,44.439791L18.98951,54.569246 0.47998798,62.66881z M17.428029,12.359973L36.955557,23.568769 21.957478,49.686174 20.847757,46.346189 15.11851,45.756407 14.138656,42.166935 8.5292659,41.966761 6.9493899,38.037481 2.4399572,38.477377z M26.812517,0.0009765625C27.350616,-0.012230873,27.875986,0.10826397,28.348372,0.3782568L42.175028,8.3180408C43.85462,9.2780154,44.234529,11.777948,43.02482,13.89789L41.375219,16.767812 21.460039,5.3381228 23.10964,2.4582005C23.979116,0.941679,25.437378,0.034730911,26.812517,0.0009765625z
            </StreamGeometry>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="Border"
                        Background="{StaticResource BrushBlueSelector}"
                        Padding="5,2"
                        SnapsToDevicePixels="true"
                        CornerRadius="3">
                    <Border.Effect>
                        <DropShadowEffect ShadowDepth="0"
                                          Color="Turquoise"
                                          BlurRadius="8" />
                    </Border.Effect>
                    <Path x:Name="buttonSymbol"
                          Data="{TemplateBinding Content}"
                          Stretch="Uniform"
                          Fill="#FFFFFFFF"
                          RenderTransformOrigin="0.5,0.5">
                        <Path.RenderTransform>
                            <TransformGroup>
                                <TransformGroup.Children>
                                    <RotateTransform Angle="0" />
                                    <ScaleTransform ScaleX="1"
                                                    ScaleY="1" />
                                </TransformGroup.Children>
                            </TransformGroup>
                        </Path.RenderTransform>
                    </Path>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver"
                             Value="True">
                        <Setter TargetName="Border"
                                Property="Background"
                                Value="{Binding Background,RelativeSource={RelativeSource TemplatedParent}}" />
                        <Setter TargetName="Border"
                                Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0"
                                                  Color="{Binding Background.Color,RelativeSource={RelativeSource TemplatedParent}}"
                                                  BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsPressed"
                             Value="True">
                        <Setter TargetName="Border"
                                Property="Background"
                                Value="{StaticResource BrushHeaderBackground}" />
                        <Setter TargetName="Border"
                                Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0"
                                                  Color="Gray"
                                                  BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled"
                             Value="False">
                        <Setter TargetName="Border"
                                Property="Background"
                                Value="Gray" />
                        <Setter TargetName="Border"
                                Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0"
                                                  Color="Gray"
                                                  BlurRadius="10" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsEditing,RelativeSource={RelativeSource AncestorType=DataGridRow}}"
                     Value="true">
            <Setter Property="Content">
                <Setter.Value>
                    <StreamGeometry>M8.1099597,36.94997L8.1099597,41.793968 39.213959,41.793968 39.213959,36.94997z M12.42,0.049999889L18.4,0.049999889 18.4,12.252 12.42,12.252z M0,0L7.9001866,0 7.9001866,14.64218 39.210766,14.64218 39.210766,0 47.401001,0 47.401001,47.917 0,47.917z</StreamGeometry>
                </Setter.Value>
            </Setter>
            <Setter Property="Background"
                    Value="Green" />
        </DataTrigger>
    </Style.Triggers>
</Style>
  • 该样式基于标准按钮而非
  • 我合并了两个模板并指定了触发器中的差异
  • 触发器基于父DataGridRow.IsEditing

这里是主窗口中的代码重写

private void EditButton_InsideDataGrid_Click(object sender, RoutedEventArgs e)
{

    int colIndex = 0;
    int rowIndex = 0;

    DependencyObject dep = (DependencyObject)e.OriginalSource;
    while (dep != null && !(dep is DataGridCell))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    if (dep == null)
        return;
    DataGridRow row = null;
    if (dep is DataGridCell)
    {

        colIndex = ((DataGridCell)dep).Column.DisplayIndex;

        while (dep != null && !(dep is DataGridRow))
        {
            dep = VisualTreeHelper.GetParent(dep);
        }

        row = (DataGridRow)dep;
        rowIndex = FindRowIndex(row);

    }

    while (dep != null && !(dep is DataGrid))
    {
        dep = VisualTreeHelper.GetParent(dep);
    }

    if (dep == null)
        return;

    DataGrid dg = (DataGrid)dep;
    if (row != null)
    {
        if (row.IsEditing)
            dg.CommitEdit(DataGridEditingUnit.Row, true);
        else
        {
            dg.CurrentCell = new DataGridCellInfo(dg.Items[rowIndex], dg.Columns[0]);
            dg.BeginEdit();
        }
    }
}

我做了一些调整来编辑并保存一行。

最后是数据网格

<DataGrid Grid.Column="1" Margin="50" ItemsSource="{Binding Names}"
            CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=.}" Width="*" Header="Names"/>
        <DataGridTemplateColumn Header="Edit" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Click="EditButton_InsideDataGrid_Click"
                            Style="{StaticResource EditSaveStyle}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

我在标准按钮上使用了样式EditSaveStyle

使用这种方法,您可能不需要继承和创建自己的按钮来切换样式等。如果您期待自定义更多,可能会引入附加属性。

这是一个工作样本ChangingStylesAtRuntime.zip

请注意,如果数据未正确绑定,或dg.CommitEdit未设置为未绑定/只读列,则IsReadOnly="True"可能会失败

答案 1 :(得分:0)

考虑使用DataTemplateSelector类。

此类提供了一种基于数据对象和数据绑定元素选择DataTemplate的方法。

<强> XAML:

<Window.Resources>
...
<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>   
...

</Window.Resources>
...
<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
         HorizontalContentAlignment="Stretch"/>

<强>类别:

public class TaskListDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate
        SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if (element != null && item != null && item is Task)
        {
            Task taskitem = item as Task;

            if (taskitem.Priority == 1)
                return
                    element.FindResource("importantTaskTemplate") as DataTemplate;
            else 
                return
                    element.FindResource("myTaskTemplate") as DataTemplate;
        }

        return null;
    }
}