programing

DataGrid 텍스트 열에 스타일을 지정할 수 없는 이유는 무엇입니까?

golfzon 2023. 5. 9. 23:26
반응형

DataGrid 텍스트 열에 스타일을 지정할 수 없는 이유는 무엇입니까?

다음에 대한 스타일을 만들려고 했습니다.DataGridTextColumn다음과 같은 코드로

<Style TargetType="{x:Type DataGridTextColumn}">
           ...
</Style>

그러나 Visual Studio 2010의 주요 기능은{x:Type DataGridTextColumn}파란색 선과 정교함이 돋보이는 제품입니다.Exception has been thrown by the target of an invocation.

이 문제가 발생하는 이유와 해결 방법은 무엇입니까?

스타일을 지정할 수 없습니다.DataGridTextColumn왜냐면DataGridTextColumn에서 파생되지 않음FrameworkElement(또는)FrameworkContentElement. FrameworkElement 등만 스타일링을 지원합니다.

다음과 같은 유형이 아닌 모든 유형에 대해 XAML에서 스타일을 작성하려고 할 수 있습니다.FrameworkElement또는FrameworkContentElement오류 메시지가 표시됩니다.

어떻게 해결합니까?다른 문제와 마찬가지로, 의지가 있는 곳에는 방법이 있습니다.이 경우 가장 쉬운 해결책은 DataGrid에 연결된 속성을 생성하여 DataGridColumn 스타일을 할당하는 것입니다.

<DataGrid ...>
  <local:MyDataGridHelper.TextColumnStyle>
    <Style TargetType="FrameworkElement">
      ... setters here ...
    </Style>
  </local:MyDataGridHelper.TextColumnStyle>
  ...

구현은 다음과 같습니다.

public class MyDataGridHelper : DependencyObject
{
  // Use propa snipped to create attached TextColumnStyle with metadata:
  ... RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
    {
      var grid = (DataGrid)obj;
      if(e.OldValue==null && e.NewValue!=null)
        grid.Columns.CollectionChanged += (obj2, e2) =>
        {
          UpdateColumnStyles(grid);
        }
    }
  }
  private void UpdateStyles(DataGrid grid)
  {
    var style = GetTextColumnStyle(grid);
    foreach(var column in grid.Columns.OfType<DataGridTextColumn>())
      foreach(var setter in style.Setters.OfType<Setter>())
        if(setter.Value is BindingBase)
          BindingOperations.SetBinding(column, setter.Property, setter.Value);
        else
          column.SetValue(setter.Property, setter.Value);
  }
}

연결된 속성이 변경될 때마다 열에 대한 처리기가 추가됩니다.그리드에서 CollectionChanged 이벤트가 발생했습니다.CollectionChanged 이벤트가 실행되면 모든 열이 설정된 스타일로 업데이트됩니다.

위의 코드는 스타일을 제거했다가 다시 추가하는 경우를 처리하지 않습니다.두 개의 이벤트 처리기가 등록되어 있습니다.정말 강력한 솔루션의 경우 이벤트 핸들러를 포함하는 다른 연결 속성을 추가하여 이벤트 핸들러를 등록 취소할 수 있도록 함으로써 이 문제를 해결하고 싶지만, 사용자의 경우에는 중요하지 않다고 생각합니다.

여기서 또 다른 주의 사항은 SetBinding 및 SetValue를 직접 사용하면 종속성 속성의 BaseValueSource가Local대신에DefaultStyle이것은 아마 당신의 경우에는 아무런 차이가 없을 것이지만, 저는 그것을 언급해야 한다고 생각했습니다.

스타일 태그는 올바른 위치에 있어야 합니다.데이터 그리드는 다음과 같이 표시될 수 있습니다.

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn />
        </DataGrid.Columns>
    </DataGrid>

처음에는 작동하지 않는 DataGridTextColumn 요소 내에 직접 스타일 태그를 추가하려고 할 수 있습니다.그러나 "DataGridTextColumn"에 대한 요소를 작성할 수 있습니다.ElementStyle" 또는 "DataGridTextColumn"입니다."DataGridTextColumn" 요소 내에서 "ElementStyle 편집"을 선택합니다.그러면 각 요소 태그에 스타일 태그가 포함될 수 있습니다.

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn>
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="Background" Value="Green"></Setter>
                    </Style>
                </DataGridTextColumn.ElementStyle>
                <DataGridTextColumn.EditingElementStyle>
                    <Style TargetType="TextBox">
                        <Setter Property="Background" Value="Orange"></Setter>
                    </Style>
                </DataGridTextColumn.EditingElementStyle>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>

하나의 스타일은 셀이 편집 모드에 있을 때 보기에 적용되고 다른 스타일은 편집 모드에 적용됩니다.볼 때는 텍스트 블록에서 편집할 때는 텍스트 상자로 변경됩니다(처음에는 텍스트 블록으로 변경되었습니다!).

이것은 Ray Burns의 답변에 더 추가된 것입니다.처음에는 혼자서는 구현할 수 없었지만 mm8(https://stackoverflow.com/a/46690951/5381620) 의 도움으로 실행할 수 있었습니다.정말 잘 작동합니다.첨부된 속성 접근 방식을 따르는 데 문제가 있는 다른 사용자에게는 전체 코드 스니펫이 도움이 될 수 있습니다.

public class MyDataGridHelper : DependencyObject
{
    private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
    {
        PropertyChangedCallback = (obj, e) =>
        {
            var grid = (DataGrid)obj;
            if (e.OldValue == null && e.NewValue != null)
                grid.Columns.CollectionChanged += (obj2, e2) =>
                {
                    UpdateColumnStyles(grid);
                };
        }
    });

    public static void SetTextColumnStyle(DependencyObject element, Style value)
    {
        element.SetValue(TextColumnStyleProperty, value);
    }
    public static Style GetTextColumnStyle(DependencyObject element)
    {
        return (Style)element.GetValue(TextColumnStyleProperty);
    }

    private static void UpdateColumnStyles(DataGrid grid)
    {
        var origStyle = GetTextColumnStyle(grid);
        foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
        {
            //may not add setters to a style which is already in use
            //therefore we need to create a new style merging
            //original style with setters from attached property
            var newStyle = new Style();
            newStyle.BasedOn = column.ElementStyle;
            newStyle.TargetType = origStyle.TargetType;

            foreach (var setter in origStyle.Setters.OfType<Setter>())
            {
                newStyle.Setters.Add(setter);
            }

            column.ElementStyle = newStyle;
        }
    }
}

목청을 돋보기

<Grid>
    <DataGrid Name="MyDataGrid" ItemsSource="{Binding Lines}" AutoGenerateColumns="False" >
        <local:MyDataGridHelper.TextColumnStyle>
            <Style TargetType="TextBlock">
                <Setter Property="TextWrapping" Value="Wrap"/>
            </Style>
        </local:MyDataGridHelper.TextColumnStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="ProductId1" Binding="{Binding Path=Result1}" />
            <DataGridTextColumn Header="ProductId2" Binding="{Binding Path=Result2}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

편집: 첫 번째 접근 방식에서는 전체 스타일을 덮어썼습니다.새로운 버전에서는 여전히 이와 같은 다른 스타일 수정 사항을 유지할 수 있습니다.

<DataGridTextColumn.ElementStyle>
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="Foreground" Value="Red"/>
    </Style>
</DataGridTextColumn.ElementStyle>

페드리토 답변에 약간 추가됩니다.모든 것이 정상적으로 작동하지만 origStyle에 기본 스타일이 있으면 기본 스타일의 세터가 삭제됩니다.

이 문제를 해결하려면 모든 설정자를 확보해야 합니다.

 private static void UpdateColumnStyles(DataGrid grid)
    {
        var origStyle = GetTextColumnStyle(grid);
        foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
        {
            //may not add setters to a style which is already in use
            //therefore we need to create a new style merging
            //original style with setters from attached property
            var newStyle = new Style();
            newStyle.BasedOn = column.ElementStyle;
            newStyle.TargetType = origStyle.TargetType;

            var baseSetters = GetBaseSetters(origStyle);
            var allSetters = baseSetters.Concat(origStyle.Setters.OfType<Setter>());

            foreach (var setter in allSetters)
            {
                newStyle.Setters.Add(setter);
            }

            column.ElementStyle = newStyle;
        }
    }

    private static IEnumerable<Setter> GetBaseSetters(Style style)
    {
        return style.BasedOn?.Setters.OfType<Setter>().Concat(GetBaseSetters(style.BasedOn)??new Setter[0]);
    }

더 단순:

<FontFamily x:Key="DefaultFont">Snap ITC</FontFamily>
<Style x:Key="ControlStyle" TargetType="Control">
    <Setter Property="FontFamily" Value="{StaticResource DefaultFont}"/>
</Style>
<Style TargetType="{x:Type DataGridCellsPresenter}" BasedOn="{StaticResource ControlStyle}">
</Style>

DataGridTextColumn은 TextBlock이 들어 있는 열에 불과합니다.TextBlock으로 TargetType을 사용하여 스타일을 작성하고 DataGridTextColumn의 ElementStyle 속성을 바인딩합니다.도움이 되길 바랍니다!

언급URL : https://stackoverflow.com/questions/2630292/why-cant-i-style-a-datagridtextcolumn

반응형