Как сделать средство выбора даты в дереве MVVM WPF

У меня довольно сложный вопрос: на моей работе мы используем WPF со стандартами MVVM. В одном из наших пользовательских элементов управления есть древовидное представление, которое загружает все таблицы из базы данных. Для каждой таблицы имя загружается в список древовидной структурой. Когда вы нажимаете на имя таблицы, вы можете добавить данные в эту таблицу с экрана. По сути, он загружает имена столбцов из таблицы сбоку и позволяет вводить данные и сохранять их. Затем записи сохраняются и добавляются в таблицу как дочерние. Отсюда, выбрав ребенка, вы сможете обновить эту информацию.

Теперь текущее приложение отлично загружает данные. Имена таблиц и данные загружены. Дочерние данные загружаются. Все хорошо, но когда дело доходит до загрузки элементов управления, мы используем только текстовые поля.

В пользовательском контроле код:

<UserControl.Resources>
    <ResourceDictionary>
        <DataTemplate x:Key="AdditionalItemsTemplate">
            <Border>
                <StackPanel>
                    <Label                             
                        Content="{Binding Name}"
                        Style="{StaticResource PanelLabelStyle}"/>
                    <TextBox                                                         
                        Text="{Binding Value}"                            
                        Style="{StaticResource TextBoxStyle}"/>

                </StackPanel>
            </Border>
        </DataTemplate>
    </ResourceDictionary>
</UserControl.Resources>
<Border 
    Height="350"
    Width="{Binding Width}"
    Style="{StaticResource InnerMenuBorderStyle}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Border
            Grid.Row="0"
            Grid.Column="0"
            Width="230"                
            IsEnabled="{Binding IsUpdateEnabled}">
            <StackPanel>
                <Border
                    Margin="3,3,3,0"
                    Style="{StaticResource PanelBorderStyle}">
                    <StackPanel>
                        <Label Style="{StaticResource PanelLabelStyle}">
                            <TextBlock
                                Text="{Binding TableName}"
                                TextWrapping="WrapWithOverflow"/>
                        </Label>
                        <TextBox
                            Style="{StaticResource TextBoxStyle}"
                            Text="{Binding Value}"
                            TextWrapping="Wrap"/>
                        <ItemsControl 
                            Width="222"
                            HorizontalAlignment="Left"
                            ItemsSource="{Binding additionalFields}" Margin="0,0,-226,0"
                            ItemTemplate="{StaticResource AdditionalItemsTemplate}"/>
                    </StackPanel>
                </Border>
                <Button      
                    Width="70"
                    VerticalAlignment="Top"
                    HorizontalAlignment="Left"
                    Margin="3.5,0,0,0"
                    Template="{StaticResource UpdateButtonTemplate}"
                    Command="{Binding ButtonCommand}"
                    CommandParameter="Update"/>
            </StackPanel>
        </Border>
        <Rectangle 
            Grid.Row="0"
            Grid.RowSpan="2"
            Grid.Column="1"              
            HorizontalAlignment="Left" 
            VerticalAlignment="Stretch" 
            Width="2" 
            StrokeDashArray="0.5 1.0 0.3" 
            Stroke="LightGray"
            Visibility="{Binding IsAddVisible}"/>
        <Border 
            Grid.Row="0"
            Grid.Column="2"
            Width="230"                
            Visibility="{Binding IsAddVisible}">
            <StackPanel>
                <Border
                    Margin="3,3,3,0"
                    Style="{StaticResource PanelBorderStyle}">
                    <StackPanel>
                        <Label
                            Grid.Row="0"
                            Content="{Binding LabelText}"
                            Style="{StaticResource PanelLabelStyle}"/>
                        <TextBox 
                            Grid.Row="1"                        
                            Text="{Binding NewLookup}"                        
                            Style="{StaticResource TextBoxStyle}"/>
                        <ItemsControl   
                            Width="222"
                            Margin="0,0,-226,0"
                            HorizontalAlignment="Left"
                            ItemsSource="{Binding childAdditionalFields}"                                 
                            ItemTemplate="{StaticResource AdditionalItemsTemplate}"/>
                    </StackPanel>
                </Border>
                <Button 
                    Grid.Row="2"
                    Width="50"
                    HorizontalAlignment="Left"
                    Margin="3.5,0,0,0"
                    Template="{StaticResource AddButtonTemplate}"                
                    Command="{Binding ButtonCommand}"
                    CommandParameter="Add"/>
            </StackPanel>
        </Border>
    </Grid>
</Border>  

В ресурсах AdditionalItemsTemplate загружает метку для каждого имени столбца, а текстовое поле загружается со значениями или может использоваться для ввода новых значений.

Я хотел бы сделать только ONE средство выбора даты для таблицы ONE. Так например. В таблице «Студенты» поля: Имя (varchar), Возраст (varchar), DateStarted (дата). Текстовое поле загружается для имени и возраста, но только для DateStarted должен загружаться указатель даты.

Пока что в ресурсах добавляю <local:DatePicker SelectedDate="{Binding Value}" Visibility="{Binding DateVisible}"/> Чтобы при загрузке таблицы Student видимость datepicker менялась со скрытой на видимую.

Вот пример ViewModel:

public AddUpdateConfigurationViewModel(TreeViewContainer treeViewContainer, List<AddChangeSiteConfigurationViewModel> lookupTypeList, FieldDataResponse fieldDataResponse)
    {
        NewLookup = String.Empty;
        Width = 480;
        DateVisible = "Hidden";
        IsAddVisible = "Hidden";
        IsUpdateEnabled = false;
        if (treeViewContainer.AdditionalFields != null)
        {
            if (treeViewContainer.AdditionalFields.Count() > 0)
            {
                treeViewContainer.AdditionalFields.RemoveAll(x => x.Name.Contains("ID"));
                treeViewContainer.AdditionalFields.RemoveAll(x => x.Name.Contains("Guid"));
            }
        }      
        if (treeViewContainer.AdditionalFields != null)
            this.additionalFields = new ObservableCollection<TreeViewContainer>(treeViewContainer.AdditionalFields);
        if ((treeViewContainer.ParentTable == null) | (treeViewContainer.ParentTable == String.Empty))
            IsUpdateEnabled = true;
        var lookupTypes = lookupTypeList.Where(x => x.Parent_Field == "ID" + treeViewContainer.TableName);
        if (treeViewContainer.ParentTable == "IsParent")
        {
            IsAddVisible = "Visible";
            DateVisible = "Hidden";
            LabelText = "New " + treeViewContainer.Name;
            TableName = treeViewContainer.TableName;
            childAdditionalFields = new ObservableCollection<TreeViewContainer>();
            foreach (var additionalField in treeViewContainer.AdditionalFields)
                childAdditionalFields.Add(new TreeViewContainer(additionalField.Name));
            if (treeViewContainer.Name.Equals("Student"))
            {

                DateVisible = "Visible";

            }
        }
        else if (lookupTypes.Count() > 0)
        {
            foreach (var lookupType in lookupTypes)
            {
                IsAddVisible = "Visible";
                LabelText = "New " + lookupType.Name;
                TableName = lookupType.TableName;
                childAdditionalFields = new ObservableCollection<TreeViewContainer>();
                foreach (var additionalChildField in lookupType.additionalFieldsDictionary)
                    childAdditionalFields.Add(new TreeViewContainer(additionalChildField.Key));
            }
        }
        else
            Width = 250;                  
        this.Name = treeViewContainer.Name;
        this.Value = treeViewContainer.Name;
        this.ID = treeViewContainer.ID;
        this.treeViewContainer = treeViewContainer;
        this.lookupTypeList = lookupTypeList;
        this.fieldDataResponse = fieldDataResponse;
    }

Я надеюсь в этом есть смысл.

Теперь, когда я загружаю пользовательский элемент управления и выбираю другую таблицу, иногда средство выбора даты отображается, даже если для видимости установлено значение «Скрытый». И когда выбрана таблица Student, под текстовыми полями для каждого поля есть средства выбора даты.

Как мне просто сделать один указатель даты для этой таблицы?

Если потребуется дополнительная информация, я отредактирую и обновлю ее соответствующим образом.

РЕДАКТИРОВАТЬ

Скриншоты Вот как загружается древовидная структура. все таблицы в базе данных перечислены здесь введите здесь описание изображениятеперь, нажав на таблицу, которая не должна иметь datepicker делает следующее: введите здесь описание изображениядобавляет средство выбора даты в этот контейнер дерева. я хочу устранить это, и здесь должно быть введите описание изображения здесьно у меня их слишком много, см. . здесь должен быть добавлен только один. не до конца, под каждым текстовым полем.

и настройка «Видимый» — это просто временное исправление, пока я не отсортирую этот указатель даты. видимость можно решить позже


person Nicholas Aysen    schedule 01.09.2014    source источник
comment
Можно ли предоставить скриншот? Я не могу представить, как это работает. Кстати. наличие DateVisible в виде строки, а не типа перечисления Visibility (или преобразование из bool -> Visibility) может быть подвержено ошибкам из-за орфографических ошибок.   -  person sondergard    schedule 01.09.2014


Ответы (1)


Я не думаю, что добавление средства выбора даты и попытка показать/скрыть его - лучший способ. Лучшим способом является загрузка шаблона данных, соответствующего типу, к которому выполняется привязка. Поэтому, если столбец имеет тип даты и времени, вы должны загрузить шаблон данных с меткой и средством выбора даты. Это то, что DataTemplateSelector предназначен для. Вы создаете класс, который расширяет DataTemplateSelector, и решаете, какой шаблон вернуть, в зависимости от объекта, к которому он привязан.

<UserControl.Resources>
    <DataTemplate x:Key="DateTimeFieldTemplate">
        <Border>
            <StackPanel>
                <Label                             
                    Content="{Binding Name}"
                    Style="{StaticResource PanelLabelStyle}"/>
                <local:DatePicker                                                         
                    SelectedDate="{Binding Value}"/>
            </StackPanel>
        </Border>
    </DataTemplate>
    <DataTemplate x:Key="TextFieldTemplate">
        <Border>
            <StackPanel>
                <Label                             
                    Content="{Binding Name}"
                    Style="{StaticResource PanelLabelStyle}"/>
                <TextBox                                                         
                    Text="{Binding Value}"                            
                    Style="{StaticResource TextBoxStyle}"/> 
            </StackPanel>
        </Border>
    </DataTemplate>
    <local:TemplateSelector x:Key="TemplateSelector" DateTimeFieldTemplate="{StaticResource DateTimeFieldTemplate}" TextFieldTemplate="{StaticResource TextFieldTemplate}"/>
</UserControl.Resources>
<Grid>
    <ItemsControl ItemsSource="{Binding Items}" ItemTemplateSelector="{StaticResource TemplateSelector}"/>
</Grid>

Вы иллюстрируете в своем исходном коде, что у вас есть свойство Name и Value, поэтому вам нужно только решить, как предоставить информацию о том, какой тип данных имеет свойство Value. Один из способов — создать интерфейс со свойством Value объекта типа:

public interface IBoundDataColumn
{
    public string Name { get; } // Not really necessary for the template selector, but perhaps for completeness
    public object Value { get; }
}

public class DateTimeColumn : IBoundDataColumn
{
    public string Name { get; set; }
    public object Value { get; set; }
}

public class TemplateSelector : DataTemplateSelector
{
    public DataTemplate TextFieldTemplate
    {
        get;
        set;
    }

    public DataTemplate DateTimeFieldTemplate
    {
        get;
        set;
    }

    public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
    {
        IBoundDataColumn boundCol = item as IBoundDataColumn;

        if (boundCol.Value.GetType() == typeof(DateTime))
        {
            return DateTimeFieldTemplate;
        }
        else
        {
            return TextFieldTemplate;
        }

        return base.SelectTemplate(item, container);
    }
}

Или у вас может быть свойство DataType:

public interface IBoundDataColumn
{
    public Type DataType {get;}
}

public class DateTimeColumn : IBoundDataColumn
{
    public string Name {get;set;}
    public DateTime Value {get;set;}
    public Type DataType { get { return typeof(DateTime); } }
}

Или вы можете вообще избежать интерфейса и использовать отражение для динамического получения типа:

public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
    var p = item.GetType().GetProperty("Value");

    if (t.PropertyType == typeof(DateTime))
    ...
}
person sondergard    schedule 03.09.2014
comment
пытаясь реализовать этот DataTemplateSelector. Кстати, что такое решение для отражения? есть ссылка для поиска? - person Nicholas Aysen; 03.09.2014
comment
Я обновил ответ, чтобы проиллюстрировать решение для отражения. - person sondergard; 03.09.2014
comment
Благодарю. поработаю над этим и отчитаюсь через день-два - person Nicholas Aysen; 03.09.2014