2014-09-01 177 views
0

我有一个相当复杂的问题: 在我的工作中,我们使用带有MVVM标准的WPF。 在我们的一个用户控件上,有一个树形视图加载数据库中的所有表。对于每个表,名称都由树视图加载到列表中。当你点击表名时,你可以从屏幕上向该表添加数据。 基本上,它从侧面的表格加载列名,并让您输入数据并保存。记录然后保存并作为孩子添加到表格中。从这里,选择一个孩子可以让你更新这些信息。如何在MVVM treeview中制作datepicker WPF

现在,当前的应用程序加载数据的罚款。表格名称和数据被加载。子数据加载。 一切都很好,但是在加载控件时,我们只使用文本框。

在用户控件的代码是:

<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 datepicker ONE表。例如, 。在表Students中,字段是Name(varchar),Age(varchar),DateStarted(date)。一个文本框加载名称和年龄,但只为DateStarted日期选择器应加载。

到目前为止,在资源中,我添加了<local:DatePicker SelectedDate="{Binding Value}" Visibility="{Binding DateVisible}"/> 因此,当加载表Student时,日期选择器的可见性从隐藏变为可见。

这里是视图模型的样本:

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; 
    } 

我希望这是有道理的。

现在当我加载usercontrol并在另一个表上选择时,即使将可见性设置为隐藏,但有时日期选择器仍可见。 当学生表被选中时,每个字段都有文本框下的日期选择器。

我该如何着手为这张桌子做一个日期选择器?

如果有任何更多的信息需要,我会编辑和更新相应

编辑

截图 这是怎样的树形负荷。 db中的所有表格都在这里列出 enter image description here 现在点击一个不应该有日期选择器的表是这样做的: enter image description here 它将datepicker添加到这个treeview容器。我想消除这个, ,这是它应该是 enter image description here 但我有太多,请参阅。这里只能添加一个。并不是每一个文本框下的所有方式。

和可见性设置只是一个临时修复,直到我得到这个日期选择器排序。知名度可以稍后解决

+0

是否可以提供屏幕截图?我无法真正想象它是如何工作的。顺便说一句。将DateVisible作为一个字符串而不是可见性枚举类型(或从bool - >可见性转换)可能容易出现拼写错误中的错误。试图实现这个DataTemplateSelector的 – sondergard 2014-09-01 15:09:03

回答

0

我不认为添加日期选择器并试图显示/隐藏它是最好的方式去。更好的方法是加载与绑定类型相匹配的数据模板。因此,如果该列是日期时间类型,则应加载包含标签和日期选择器的数据模板。这是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> 

你说明你有一个名称和值属性的原代码,所以你只需要在如何提供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); 
    } 
} 

或者你可以有一个数据类型属性:

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)) 
    ... 
} 
+0

。顺便说一句,反射解决方案是什么?有没有链接让我搜索? – 2014-09-03 10:43:17

+0

我已经更新了答案,以说明反思解决方案 – sondergard 2014-09-03 12:34:53

+0

谢谢。会在一两天内完成并报告 – 2014-09-03 12:46:58