Изменить стиль кнопки динамически

1

Я определил два разных стиля в 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>

И вот это событие click:

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.
......
......
......

Теперь, когда я добавляю указанный ниже код в событие Click элемента editButton:

    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. Но проблема остается такой же.

  • 1
    Это не очень распространенный способ, как решить этот тип действия. Это очень некрасивое и не простое решение. Попробуйте создать собственную кнопку и создать свойство зависимости, например, Mode = Edit / Save, и в некоторых триггерах или раскадровках вы можете изменять только те значения, которые вам нужны. Не стиль всей кнопки.
  • 0
    @YoYo Я успешно реализовал твою идею. Но проблема остается той же. Вот новый пример: drive.google.com/file/d/0B5WyqSALui0bUGxRRklDOUpKRms/…
Теги:
wpf
datagrid
styles

2 ответа

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

здесь переписывается код в главном окне.cs

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" должным образом или IsReadOnly="True" не установлена для столбцов без привязки/чтения

  • 0
    Благодарю. Я попытался реализовать ваш ответ в моем примере проекта, а также в моем реальном проекте. Я получил разницу в обоих проектах. В моем примере проекта все работает нормально. Но в моем реальном проекте я не вижу никаких значков, таких как карандаш или дискета на кнопке. Можете ли вы сказать мне проблему.
  • 0
    @Vishal, у вас все еще есть проблема с отсутствующим значком? Отсутствующий значок может быть связан с содержимым, установленным в самой кнопке, поскольку стиль не может переопределить локальные значения. поэтому удалите любое содержимое с кнопок, например <Button Content="content"/> или <Button>content</Button> . если проблема все еще сохраняется, мне может понадобиться увидеть фактическую реализацию.
Показать ещё 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;
    }
}
  • 0
    Как вы описали здесь, DataTemplateSelector предоставляет способ выбора DataTemplate на основе объекта данных и коллекции данных. Но если вы посмотрите на мой вопрос, я не хочу менять шаблон DataGridRows. Я просто хочу изменить ControlTemplate кнопки внутри dataGrid. Когда кнопка инициализируется, она получает ControlTemplate кнопки Edit. Когда пользователь нажимает на нее, шаблон ControlTemplate этой кнопки должен быть переключен на кнопку «Сохранить». И снова кнопка «Изменить» при нажатии и так далее ....... Спасибо за вашу попытку.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню