2016-07-27 41 views
0

作爲主題暗示我不想修改CollectionEditorPicker的內容。此控件用於打開嵌套屬性列表的浮動窗口。 不幸的是,RadPropertyGrid不顯示有關該字段中的集合的任何信息。 我怎樣才能在那裏設置一些價值?例如,「點擊此處打開集合」或「xx Items」或「Item 1,Item 2,Item 3 ...」等佔位符,請參閱有關該字段的一些預覽或信息。Telerik RadPropertyGrid CollectionEditorPicker的內容

我試着用模板選擇器,但如果我這樣做,打開的彈出窗口不能再調整大小。它也丟失了默認的CollectionEditorPicker中的一些信息。 你能幫我嗎?

下面是一個最小工作示例。

的XAML:

<Window x:Class="TelerikPropertyGridTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" 
     xmlns:model="clr-namespace:TelerikPropertyGridTest.Model" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.Resources> 
      <model:TemplateSelector x:Key="RadPropertyListTemplateSelector"> 
       <!-- Not Working --> 
       <model:TemplateSelector.CollectionsDataTemplate> 
         <DataTemplate> 
          <telerik:RadDropDownButton Content="Test"> 
           <telerik:RadDropDownButton.DropDownContent> 
            <telerik:CollectionEditor telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Source" 
                  ></telerik:CollectionEditor> 
           </telerik:RadDropDownButton.DropDownContent> 
          </telerik:RadDropDownButton> 
         </DataTemplate> 
       </model:TemplateSelector.CollectionsDataTemplate> 
       <model:TemplateSelector.FloatNumberTemplate> 
        <DataTemplate> 
         <telerik:RadNumericUpDown telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Value" /> 
        </DataTemplate> 
       </model:TemplateSelector.FloatNumberTemplate> 
       <model:TemplateSelector.IntNumberTemplate> 
        <DataTemplate> 
         <telerik:RadNumericUpDown telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Value" 
                NumberDecimalDigits="0" /> 
        </DataTemplate> 
       </model:TemplateSelector.IntNumberTemplate> 
      </model:TemplateSelector> 
     </Grid.Resources> 
     <telerik:RadPropertyGrid Item="{Binding ObjectToBind}" 
           AutoGeneratingPropertyDefinition="RadPropertyGrid_OnAutoGeneratingPropertyDefinition" 
           EditorTemplateSelector="{StaticResource RadPropertyListTemplateSelector}"> 
     </telerik:RadPropertyGrid> 
    </Grid> 
</Window> 

的視圖模型(生成用於測試的隨機對象)

public class MainWindowViewModel : BindableBase 
{ 

    private readonly Random _random = new Random(); 

    private IExampleInterface _objectToBind; 

    public MainWindowViewModel() 
    { 
     this.ObjectToBind = new ExampleImplementation 
          { 
           SomeBooleanValue = this._random.Next() % 2 == 1, 
           SomeDateValue = this.RandomDay(), 
           SomeIntValue = this._random.Next(), 
           SomeString = Guid.NewGuid().ToString(), 
           SubClasses = new List<IExampleInterface> 
              { 
               new ExampleImplementation 
               { 
                SomeBooleanValue = this._random.Next() % 2 == 1, 
                SomeDateValue = this.RandomDay(), 
                SomeIntValue = this._random.Next(), 
                SomeString = Guid.NewGuid().ToString(), 
                SubClasses = new List<IExampleInterface> 
                    { 
                     new ExampleImplementation 
                     { 
                      SomeBooleanValue = 
                       this._random.Next() % 2 == 1, 
                      SomeDateValue = this.RandomDay(), 
                      SomeIntValue = this._random.Next(), 
                      SomeString = Guid.NewGuid().ToString() 
                     } 
                    } 
               } 
              } 
          }; 
    } 

    public IExampleInterface ObjectToBind 
    { 
     get { return this._objectToBind; } 
     set 
     { 
      if (this._objectToBind != value) 
      { 
       this._objectToBind = value; 
       this.OnPropertyChanged("ObjectToBind"); 
      } 
     } 
    } 

    private DateTime RandomDay() 
    { 
     var start = new DateTime(1995, 1, 1); 
     var range = (DateTime.Today - start).Days; 
     return start.AddDays(this._random.Next(range)); 
    } 

} 

的IExampleInterface(應該是後來在真實接口):

public interface IExampleInterface 
{ 
    string SomeString { get; set; } 
    int SomeIntValue { get; set; } 
    double SomeDouble { get; set; } 
    IList<IExampleInterface> SubClasses { get; set; } 
    IList<IExampleInterface> SubClasses2 { get; set; } 
    bool SomeBooleanValue { get; set; } 
    DateTime SomeDateValue { get; set; } 
    SomeEnum SomeEnumValue { get; set; } 
} 

ExampleImplementation(稍後將在具有附加屬性的Real Implementation中實現)。

public class ExampleImplementation : BindableBase, IExampleInterface 
{ 

    private bool _someBooleanValue; 
    private DateTime _someDateValue; 
    private double _someDouble; 
    private SomeEnum _someEnumValue; 
    private int _someIntValue; 
    private string _someString; 
    private ObservableCollection<IExampleInterface> _subClasses; 

    private ObservableCollection<IExampleInterface> _subClasses2; 

    public bool SomeBooleanValue 
    { 
     get { return this._someBooleanValue; } 
     set 
     { 
      if (this._someBooleanValue != value) 
      { 
       this._someBooleanValue = value; 
       this.OnPropertyChanged("SomeBooleanValue"); 
      } 
     } 
    } 

    public DateTime SomeDateValue 
    { 
     get { return this._someDateValue; } 
     set 
     { 
      if (this._someDateValue != value) 
      { 
       this._someDateValue = value; 
       this.OnPropertyChanged("SomeDateValue"); 
      } 
     } 
    } 

    public double SomeDouble 
    { 
     get { return this._someDouble; } 
     set 
     { 
      if (Math.Abs(this._someDouble - value) > 0.01) 
      { 
       this._someDouble = value; 
       this.OnPropertyChanged("SomeDouble"); 
      } 
     } 
    } 

    public SomeEnum SomeEnumValue 
    { 
     get { return this._someEnumValue; } 
     set 
     { 
      if (this._someEnumValue != value) 
      { 
       this._someEnumValue = value; 
       this.OnPropertyChanged("SomeEnumValue"); 
      } 
     } 
    } 

    public int SomeIntValue 
    { 
     get { return this._someIntValue; } 
     set 
     { 
      if (this._someIntValue != value) 
      { 
       this._someIntValue = value; 
       this.OnPropertyChanged("SomeIntValue"); 
      } 
     } 
    } 

    [Display(Name = @"TestString", GroupName = @"TestGroup", Description = @"TestDescription")] 
    public string SomeString 
    { 
     get { return this._someString; } 
     set 
     { 
      if (this._someString != value) 
      { 
       this._someString = value; 
       this.OnPropertyChanged("SomeString"); 
      } 
     } 
    } 

    [Display(Name = @"Some Subclasses")] 
    public IList<IExampleInterface> SubClasses 
    { 
     get { return this._subClasses; } 
     set 
     { 
      if (!Equals(this._subClasses, value)) 
      { 
       this._subClasses = new ObservableCollection<IExampleInterface>(value); 
       this.OnPropertyChanged("SubClasses"); 
      } 
     } 
    } 

    public IList<IExampleInterface> SubClasses2 
    { 
     get { return this._subClasses2; } 
     set 
     { 
      if (!Equals(this._subClasses2, value)) 
      { 
       this._subClasses2 = new ObservableCollection<IExampleInterface>(value); 
       this.OnPropertyChanged("SubClasses2"); 
      } 
     } 
    } 

} 

最後的TemplateSelector

public class TemplateSelector : DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     var def = item as PropertyDefinition; 
     if (def == null || def.SourceProperty == null) 
     { 
      return base.SelectTemplate(item, container); 
     } 

     if (typeof (IEnumerable).IsAssignableFrom(def.SourceProperty.PropertyType) && typeof(string) != def.SourceProperty.PropertyType) 
     { 
      return this.CollectionsDataTemplate; 
     } 

     if (typeof (double).IsAssignableFrom(def.SourceProperty.PropertyType)) 
     { 
      return this.FloatNumberTemplate; 
     } 

     if (typeof (int).IsAssignableFrom(def.SourceProperty.PropertyType)) 
     { 
      return this.IntNumberTemplate; 
     } 

     return base.SelectTemplate(item, container); 
    } 

    public DataTemplate CollectionsDataTemplate { get; set; } 
    public DataTemplate FloatNumberTemplate { get; set; } 
    public DataTemplate IntNumberTemplate { get; set; } 
} 

This is what I expect

最佳的解決方案是將獲取詳細信息TextBlock中的,像第1項,第2項等

謝謝。

//編輯: 我已經想出了NullReferenceException並獲得了一個Demo來工作,以便我可以修改文本。但彈出與默認不同。你有想法解決它嗎?

我已更新文本和示例。

+0

我已經注意到,RadPropertyGrid調用標準 '字符串的ToString()' 方法只要它擊中了一個類的子類。如果它是一個集合,則該描述字段中不顯示任何內容。但是,如果您在ObservableCollection上調用ToString(),它確實會返回適當的名稱空間和類名稱 - 如預期的那樣。我想知道這是否是因爲ToString()在ObservableCollection的情況下根本不會被調用(通過Telerik的決定),或者是因爲ToString()在多態堆棧下的一些其他實現被調用。 –

+0

如果您的子類是集合,則可以使用overriden ToString()派生自己的類。 Override ToString()作爲擴展方法將不起作用。 –

回答

0

現在浪費了幾個小時後,我想出了一個解決方案來實現這一點。

我已將自定義行爲添加到集合模板。此行爲在加載或更新後立即設置CollectionEditor的標題。

下面你可以看到我的修改:

模板:

<model:TemplateSelector.CollectionsDataTemplate> 
    <DataTemplate> 
     <telerik:RadDropDownButton Content="Click to edit the collection"> 
      <telerik:RadDropDownButton.DropDownContent> 
       <telerik:CollectionEditor telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Source" 
              ResizeGripperVisibility="Visible"> 
        <i:Interaction.Behaviors> 
         <model:CollectionEditorBehavior /> 
        </i:Interaction.Behaviors> 
       </telerik:CollectionEditor> 
      </telerik:RadDropDownButton.DropDownContent> 
     </telerik:RadDropDownButton> 
    </DataTemplate> 
</model:TemplateSelector.CollectionsDataTemplate> 

行爲:

internal class CollectionEditorBehavior : Behavior<CollectionEditor> 
{ 

    protected override void OnAttached() 
    { 
     this.AssociatedObject.SourceUpdated += (sender, args) => this.PrepareHeader(); 
     this.AssociatedObject.DataContextChanged += (sender, args) => this.PrepareHeader(); 
     this.AssociatedObject.Loaded += (sender, args) => this.PrepareHeader(); 
    } 

    private void PrepareHeader() 
    { 
     if (this.AssociatedObject == null) 
     { 
      // Error Case 
      return; 
     } 

     if (this.AssociatedObject.CollectionView == null || 
      this.AssociatedObject.CollectionView.SourceCollection == null) 
     { 
      // Source not set 
      this.AssociatedObject.Header = "Collection"; 
      return; 
     } 

     // Get the property from the DataContext to retrieve HeaderInformation 
     var propInfo = this.AssociatedObject.DataContext 
          .GetType() 
          .GetProperties() 
          .FirstOrDefault(
              propertyInfo => 
              Equals(propertyInfo.GetValue(this.AssociatedObject.DataContext), 
                this.AssociatedObject.CollectionView.SourceCollection)); 


     if (propInfo == null) 
     { 
      // We didn't got the property Information, using default value 
      this.AssociatedObject.Header = "Collection"; 
      return; 
     } 

     // Getting the DisplayName Attribute 
     var attr = Attribute.GetCustomAttribute(propInfo, 
               typeof (DisplayNameAttribute)) as DisplayNameAttribute; 

     if (attr != null) 
     { 
      // We have a DisplayName attribute 
      this.AssociatedObject.Header = attr.DisplayName; 
      return; 
     } 

     // Alternative: Get the Display Attribute 
     var attr2 = Attribute.GetCustomAttribute(propInfo, 
               typeof (DisplayAttribute)) as DisplayAttribute; 
     if (attr2 != null) 
     { 
      // We have the Display Attribute 
      this.AssociatedObject.Header = attr2.Name; 
      return; 
     } 

     // We have no DisplayAttribute and no DisplayName attribute, set it to the PropertyName 
     this.AssociatedObject.Header = propInfo.Name; 
    } 

} 
相關問題