Селектор DataTemplate после набора DataContext - PullRequest
1 голос
/ 22 апреля 2020

У меня есть DataGrid с 2 столбцами. Основываясь на первом столбце, который связан с ParameterDataType, я хочу загрузить соответствующий шаблон во втором столбце.

Проблема с этим кодом связана с тем, что перед загрузкой DataGrid выполняется селектор шаблонов, в результате элемент становится нулевым. Есть ли способ выполнить Выбор шаблона после того, как DataContext ControlTemplate установлен. Пожалуйста, помогите.

Вот мой xaml:

<uwpControls:DataGrid Grid.Row="4"
                              ItemsSource="{x:Bind ViewModel.ServiceMethodsData,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                               AutoGenerateColumns="False">

<uwpControls:DataGrid.Resources>
                <DataTemplate x:Key="StringTemplate">
                    <TextBox Width="150" Height="30" VerticalAlignment="Center"></TextBox>
                </DataTemplate>
                <DataTemplate x:Key="IntegerTemplate">
                    <controls:TextBoxNumeric Width="150" Height="30" VerticalAlignment="Center"></controls:TextBoxNumeric>
                </DataTemplate>
                <DataTemplate x:Key="BooleanTemplate">
                    <CheckBox IsChecked="False"></CheckBox>
                </DataTemplate>
                <local:MethodValueDataTemplateSelector x:Key="MethodValueTemplateSelector"
                                               StringTemplate="{StaticResource StringTemplate}"
                                               IntegerTemplate="{StaticResource IntegerTemplate}"
                                               BooleanTemplate="{StaticResource BooleanTemplate}"/>
            </uwpControls:DataGrid.Resources>

 <uwpControls:DataGrid.Columns>

                <uwpControls:DataGridTextColumn Header="First Column"  
                                                Binding="{Binding ParameterDataType, Mode=OneWay}"/>

                <uwpControls:DataGridTemplateColumn Header="Second Column">
                    <uwpControls:DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentControl x:Name="MethodValueContentControl"
                                            Content="{Binding Path=.}"
                                            ContentTemplateSelector="{StaticResource MethodValueTemplateSelector}"></ContentControl>
                        </DataTemplate>
                    </uwpControls:DataGridTemplateColumn.CellTemplate>
                </uwpControls:DataGridTemplateColumn>
            </uwpControls:DataGrid.Columns>
        </uwpControls:DataGrid>

Вот мой селектор DataTemplate

public class MethodValueDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate StringTemplate { get; set; }
        public DataTemplate IntegerTemplate { get; set; }
        public DataTemplate BooleanTemplate { get; set; }

        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            //I want to do something like if(DataContext.ParameterDataType=="Int") return IntegerTemplate etc
            return StringTemplate;
        }
    }

Вот мой ViewModel

public class ServiceUtilityMethodsViewModel
{
        private ObservableCollection<VmServiceMethodsViewDataGridModel> _serviceMethodsData;
        public ObservableCollection<VmServiceMethodsViewDataGridModel> ServiceMethodsData
        {
            get => _serviceMethodsData;
            set => Set(ref _serviceMethodsData, value);
        }

        public ServiceUtilityMethodsViewModel(INavigationService navigationService) : base(navigationService)
        {
            PopulateServiceData();
        }

        private void PopulateServiceData()
        {
            ServiceMethodsData = new ObservableCollection<VmServiceMethodsViewDataGridModel>();
            ServiceMethodsData.Add(new VmServiceMethodsViewDataGridModel()
            {
                ParameterName = "Param1",
                ParameterDataType = "String"
            });
            ServiceMethodsData.Add(new VmServiceMethodsViewDataGridModel()
            {
                ParameterName = "Param2",
                ParameterDataType = "Int"
            });
            ServiceMethodsData.Add(new VmServiceMethodsViewDataGridModel()
            {
                ParameterName = "Param3",
                ParameterDataType = "bool"
            });
        }
    }
}

Вот моя модель класса

public class VmServiceMethodsViewDataGridModel : BindableBaseThreadSafe
    {
        private string _parameterName;
        private string _parameterDataType;

        public string ParameterName
        {
            get => _parameterName;
            set => Set(ref _parameterName, value);
        }
        public string ParameterDataType //I want the template selector to work based on this column.
        {
            get => _parameterDataType;
            set => Set(ref _parameterDataType, value);
        }
    }

1 Ответ

1 голос
/ 22 апреля 2020

Вы должны назначить DataTemplateSelector для DataGridTemplateColumn.CellTemplateSelector и DataGridTemplateColumn.CellEditingTemplateSelector напрямую.

Я не проверял версию UWP. Я думаю, что UWP DataGridTemplateColumn не имеет этого свойства селектора шаблона. В этом случае вы можете придерживаться своего текущего XAML, но не забудьте также определить CellEditingTemplate (например, замените TextBlock на TextBox для CellEditingTemplate версии - лучше использовать TextBlock в ваш по умолчанию CellTemplate, как это выглядит лучше). Свойства CellTemplate и CellEditingTemplate наверняка существуют в версии UWP.

XAML DataGrid определение

<uwpControls:DataGrid ItemsSource="{x:Bind ViewModel.ServiceMethodsData,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                      AutoGenerateColumns="False">
  <uwpControls:DataGrid.Resources>
    <DataTemplate x:Key="StringTemplate">
      <TextBox Width="150" Height="30" VerticalAlignment="Center" />
    </DataTemplate>
    <DataTemplate x:Key="IntegerTemplate">
      <controls:TextBoxNumeric Width="150" Height="30" VerticalAlignment="Center" />
    </DataTemplate>
    <DataTemplate x:Key="BooleanTemplate">
      <CheckBox IsChecked="False" />
    </DataTemplate>

    <local:MethodValueDataTemplateSelector x:Key="MethodValueTemplateSelector"
                                           StringTemplate="{StaticResource StringTemplate}"
                                           IntegerTemplate="{StaticResource IntegerTemplate}"
                                           BooleanTemplate="{StaticResource BooleanTemplate}" />
  </uwpControls:DataGrid.Resources>

  <uwpControls:DataGrid.Columns>
    <uwpControls:DataGridTextColumn Header="First Column"  
                                    Binding="{Binding ParameterDataType, Mode=OneWay}" />
    <uwpControls:DataGridTemplateColumn Header="Second Column"
                                        CellTemplateSelector="{StaticResource MethodValueTemplateSelector}"
                                        CellEditingTemplateSelector="{StaticResource MethodValueTemplateSelector}">
    </uwpControls:DataGridTemplateColumn>
  </uwpControls:DataGrid.Columns>
</uwpControls:DataGrid>

DataTemplateSelector также довольно просто.
Параметрами переопределения SelectTemplateCore являются элемент и контейнер элемента (который в большинстве случаев является FrameWorkElement и ContentControl).
Элементом всегда является модель данных, а DataContext текущей строки. В вашем случае товар имеет тип VmServiceMethodsViewDataGridModel.

Контейнер - это FrameWorkElement, который обертывает модель для рендеринга, например, ListBoxItem. В вашем случае контейнер должен иметь тип DataGridRow.

Просто приведите параметр элемента к соответствующему типу и оцените его.

MethodValueDataTemplateSelector.cs

public class MethodValueDataTemplateSelector : DataTemplateSelector
{
  public DataTemplate StringTemplate { get; set; }
  public DataTemplate IntegerTemplate { get; set; }
  public DataTemplate BooleanTemplate { get; set; }

  protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
  {
    // Return if the control is not loaded yet and the item is therefore null    
    // or the item is of the wrong type
    if (!(item is VmServiceMethodsViewDataGridModel dataModel))
    {
      return null;
    }

    // I want to do something like: 
    // if(DataContext.ParameterDataType=="Int") return IntegerTemplate etc
    switch (dataModel.ParameterDataType)
    {
      case string value when value.Equals("Int", StringComparison.OrdinalIgnoreCase): 
        return IntegerTemplate;
      case string value when value.Equals("String", StringComparison.OrdinalIgnoreCase): 
        return StringTemplate;
      case string value when value.Equals("Bool", StringComparison.OrdinalIgnoreCase): 
        return BooleanTemplate;
      default: 
        return null;
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...