This project has moved and is read-only. For the latest updates, please go here.

Problem with Propertygrid and fonts

Nov 30, 2013 at 3:06 PM
Edited Nov 30, 2013 at 3:23 PM
Is there a requirement to create a custom TypeConverter or TypeEditor for fonts? I can't seem to get fonts to display properly. I am converting a Windows Forms desktop app to WPF desktop app.
 // Property in class
private Font _editorFont;

 [Category( "Workspace" ),
 Description( "The font used for editing documents." ),
 DisplayName( "Editor Font" ),
 ExpandableObject]
 public Font EditorFont
 {
     get { return _editorFont; }
     set { _editorFont = value; }
 }
Dec 2, 2013 at 8:04 PM
Hi,

What exactly are you trying to do ? Can you provide a snippet ?

Here's a test :
In XAML :
<Grid>
        <xctk:PropertyGrid x:Name="_propertyGrid" />
</Grid>

In Code-Behind :
 public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();

      _propertyGrid.SelectedObject = new MyTest()
      {
        EditorFont = new Font()
        {
          MyFontFamily = new FontFamily("Stencil"),
          Size = 13
        }
      }; 
    }
  }

  public class MyTest
  {
    // Property in class
    private Font _editorFont;

    [Category( "Workspace" ),
    Description( "The font used for editing documents." ),
    DisplayName( "Editor Font" ),
    ExpandableObject()]
    public Font EditorFont
    {
      get
      {
        return _editorFont;
      }
      set
      {
        _editorFont = value;
      }
    }
  }

  [TypeConverter(typeof(FontConverter))]
  public class Font
  {
    public FontFamily MyFontFamily
    {
      get;
      set;
    }

    public int Size
    {
      get;
      set;
    }
  }

  public class FontConverter : TypeConverter
  {
    public FontConverter()
    {
    }

    public override bool CanConvertTo( ITypeDescriptorContext context, Type destinationType )
    {
      return ( destinationType == typeof( string ) )
        || base.CanConvertTo( context, destinationType );
    }

    public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourceType )
    {
      return ( sourceType == typeof( string ) )
        || base.CanConvertFrom( context, sourceType );
    }

    public override object ConvertTo( ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType )
    {
      if( ( destinationType == typeof( string ) ) )
      {
        return "My Font";
      }
      return base.ConvertTo( context, culture, value, destinationType );
    }

    public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo currentCulture, object value )
    {
      if( value != null && ( value is string ) )
      {
        return new Font();
      }
      return base.ConvertFrom( context, currentCulture, value );
    }
  }
Dec 3, 2013 at 2:17 AM
Edited Dec 3, 2013 at 3:01 AM
I was playing around the the PropertyGrid and I created a simple project to test the WPF PropertyGrid. Using a standard Windows.Forms PropertyGrid and the System.Drawing.Font object you can simply create a property the the Font type and the PropertyGrid displays it using the default TypeEditor. With the WPF PropertyGrid in the Toolkit, this was not the case.

My original question was whether or not I needed to create my own TypeEditor(s) for such objects. When the Preferences is set as the SelectedObject the propertyGrid displays the font property but nothing happens when I try to change it. Sorry for the lengthy code.

The preferences class:
    [Serializable]
    public class Preferences
    {
        private WpFFont _editorFont =  new WpFFont( 
            new FontFamily("Segoe UI"), 
            9.75F, FontWeights.Normal, 
            FontStyles.Normal, FontStretches.Normal );

        [Category("Editor"),
        DisplayName("Font"),
        Description("The font used for the editor.")]
        public WpFFont EditorFont
        {
            get { return _editorFont; }
            set { _editorFont = value; }
        }
    }
The custom font class:
    [Serializable, ExpandableObject]
    public class WpFFont
    {
        private FontFamily _family;
        private FontStyle _style;
        private FontStretch _stretch;
        private FontWeight _weight;
        private double _size;

        public FontFamily Family
        {
            get { return _family; }
            set { _family = value; }
        }
        public FontWeight Weight
        {
            get { return _weight; }
            set { _weight = value; }
        }
        public FontStretch Stretch
        {
            get { return _stretch; }
            set { _stretch = value; }
        }
        public double FontSize
        {
            get { return _size; }
            set { _size = value; }
        }
        public FontStyle Style
        {
            get { return _style; }
            set { _style = value; }
        }

        public WpFFont() { }

        public WpFFont( FontFamily family, double fontSize, FontWeight weight, FontStyle style, FontStretch stretch )
        {
            this.Family = family;
            this.FontSize = fontSize;
            this.Weight = weight;
            this.Style = style;
            this.Stretch = stretch;
        }

        public override string ToString()
        {
            return string.Format( "{0},{1},{2},{3},{4}", Family, FontSize, Weight, Style, Stretch );
        }
    }
I have written help documentation myself and it can be a arduous task. Too bad there is not better documentation for the Toolkit.

Regards,
Mark
Dec 3, 2013 at 2:00 PM
Hi Mark,

From what I understand, you want to see the new Font modified in the propertyGrid. I added a button and when clicked, the Font of the PropertyGrid.SelectedObject is modified :
Preferences pref = null;
pref = new Preferences();
_propertyGrid.SelectedObject = pref;

private void Button_Click_1( object sender, RoutedEventArgs e )
 {
      pref.EditorFont = new WpFFont( new FontFamily( "Arial" ), 17F, FontWeights.Bold,
                                               FontStyles.Italic, FontStretches.Normal );
 }
You have 2 options to reflect the changes in the propertyGrid:
Option 1)
You can call "_propertyGrid.Update()" right after the assignment of pref.EditorFont in the Button_Click_1 method. This will force an update of all properties in the propertyGrid.

Option 2)
The "Preferences" class can implement the interface "INotifyPropertyChanged" and look like this :
 public class Preferences : INotifyPropertyChanged
  {
    private WpFFont _editorFont = new WpFFont( new FontFamily( "Segoe UI" ), 9.75F, FontWeights.Normal,
                                               FontStyles.Normal, FontStretches.Normal );

    [Category( "Editor" ),
    DisplayName( "Font" ),
    Description( "The font used for the editor." )]
    public WpFFont EditorFont
    {
      get
      {
        return _editorFont;
      }
      set
      {
        _editorFont = value;
        this.OnPropertyChanged( "EditorFont" );
      }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged( string name )
    {
      if( PropertyChanged != null )
      {
        PropertyChanged( this, new PropertyChangedEventArgs( name ) );
      }
    }
    #endregion
  }
This way, the PropertyGrid will be notified of a propertyChange on its selectedObject and will update.
Dec 3, 2013 at 2:19 PM
Edited Dec 3, 2013 at 2:54 PM
There is already a built-in PropertyValueChanged event. I got it to work; however, some fonts don't update the stretch and style, The result is changing the text font for the textBox control, but the base property that displays the ToString() value does not change when the properties are changed.

Thanks for the help!
        private void testPropertyGrid_PropertyValueChanged( object sender, Xceed.Wpf.Toolkit.PropertyGrid.PropertyValueChangedEventArgs e )
        {
            if ( e.OldValue != e.NewValue )
            {
                try
                {
                    // A lot of code just to update a font in a control.
                    testStringTextBox.FontFamily = preferences.EditorFont.Family;
                    testStringTextBox.FontSize = preferences.EditorFont.FontSize;
                    testStringTextBox.FontStretch = preferences.EditorFont.Stretch;
                    testStringTextBox.FontStyle = preferences.EditorFont.Style;
                    testStringTextBox.FontWeight = preferences.EditorFont.Weight;
                }
                catch(Exception ex)
                {
                    MessageBox.Show( ex.Message, "Exception Error", MessageBoxButton.OK, MessageBoxImage.Error );
                }
            }
        }
Dec 3, 2013 at 9:59 PM
Hi,

Concerning the ToString() value that doesn't change when the properties are changed : Please have a look at this discussion : http://wpftoolkit.codeplex.com/discussions/452722.

You could do something like that :
 <xctk:PropertyGrid x:Name="_propertyGrid">
            <xctk:PropertyGrid.EditorDefinitions>
                <xctk:EditorTemplateDefinition TargetProperties="EditorFont">
                <xctk:EditorTemplateDefinition.EditingTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <!-- When using SelectedObject[s], the DataContext will be the PropertyItem. Bind to the "Value" property. -->
                            <TextBlock Text="{Binding Value.Family}" />
                            <TextBlock Text=", " />
                            <TextBlock Text="{Binding Value.FontSize}" />
                            <TextBlock Text=", " />
                            <TextBlock Text="{Binding Value.Weight}" />
                            <TextBlock Text=", " />
                            <TextBlock Text="{Binding Value.Style}" />
                            <TextBlock Text=", " />
                            <TextBlock Text="{Binding Value.Stretch}" />
                        </StackPanel>
                    </DataTemplate>
                </xctk:EditorTemplateDefinition.EditingTemplate>
            </xctk:EditorTemplateDefinition>
            </xctk:PropertyGrid.EditorDefinitions>
        </xctk:PropertyGrid>
Dec 5, 2013 at 1:48 AM
Thanks! I will give it a try.