Author Topic: Import text style, dim style, leader style drop down list from Autocad  (Read 5788 times)

0 Members and 1 Guest are viewing this topic.

latour_g

  • Newt
  • Posts: 184
My mistake, I guess it should be more that :

ItemsSource="{Binding ts}"

Okay I will check that, thanks !

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Hi,

Here's a little sample which shows how this can be done with WPF and code behind.

The PaletteTab.xaml file:
- the combo box ItemsSource is bound to the Textstyles property (DataItemCollection) defined in the code behind and the display member is the Name of each item.
- each control is named to be used in the code behind
Code - XML: [Select]
  1. <UserControl x:Class="WpfUiBindingSample.PaletteTab"
  2.             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.             xmlns:local="clr-namespace:WpfUiBindingSample"
  7.             mc:Ignorable="d"
  8.             d:DesignHeight="300" d:DesignWidth="300">
  9.     <StackPanel Background="WhiteSmoke">
  10.         <ComboBox x:Name="cbxTextstyle" HorizontalAlignment="Stretch" Margin="20"
  11.                  ItemsSource="{Binding TextStyles}" DisplayMemberPath="Name"/>
  12.         <Button x:Name="btnDoIt" Content="DO IT" Width="80" Click="btnDoIt_Click"/>
  13.     </StackPanel>
  14. </UserControl>

The code behind, PaletteTab.xaml.cs file:
- the DataContext is set to this class where the TextStyles property is defined using UIBindings.Collections.TextStyles
- event handlers use control names
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Windows.Data;
  2. using System.Collections.Specialized;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  6.  
  7. namespace WpfUiBindingSample
  8. {
  9.     public partial class PaletteTab : UserControl
  10.     {
  11.         public PaletteTab()
  12.         {
  13.             InitializeComponent();
  14.             DataContext = this;
  15.             cbxTextstyle.SelectedItem = TextStyles.CurrentItem;
  16.             TextStyles.CollectionChanged += TextStyles_CollectionChanged;
  17.         }
  18.  
  19.         public DataItemCollection TextStyles => AcAp.UIBindings.Collections.TextStyles;
  20.  
  21.         private void btnDoIt_Click(object sender, RoutedEventArgs e)
  22.         {
  23.             AcAp.ShowAlertDialog(((INamedValue)cbxTextstyle.SelectedItem).Name);
  24.         }
  25.  
  26.         private void TextStyles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  27.         {
  28.             cbxTextstyle.SelectedItem = TextStyles.CurrentItem;
  29.         }
  30.     }
  31. }
Speaking English as a French Frog

Jeff H

  • Needs a day job
  • Posts: 6150

Good stuff and thanks everyone.I have never used those collections but is the control bounded to the Active Document textstyles, and does it update collection when switching documents?





gile

  • Gator
  • Posts: 2507
  • Marseille, France
@Jeff H,

Yes it is and yes it does.
DataItemCollection is an 'observable collection'.
« Last Edit: May 11, 2016, 09:48:59 AM by gile »
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Here's the same little sample but using MVVM design pattern.
This may seem unnecessarily verbose and complex for such a simple task, but as the saying MexicanCustard, it is better to start directly with this architecture.

With MVVM, it takes full advantages of the Binding. It is not necessary to name the controls, they're simply bound to properties the ViewModel.
The XAML file:
Code - XML: [Select]
  1. <UserControl x:Class="MVVMUIBindingSample.View.PaletteTab"
  2.             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.             xmlns:local="clr-namespace:MVVMUIBindingSample.View"
  7.             mc:Ignorable="d"
  8.             d:DesignHeight="300" d:DesignWidth="300">
  9.     <StackPanel Background="WhiteSmoke">
  10.         <ComboBox HorizontalAlignment="Stretch" Margin="20"
  11.                  ItemsSource="{Binding TextStyles}" DisplayMemberPath="Name" SelectedItem="{Binding TextStyle}"/>
  12.         <Button Content="DO IT" Width="80" Command="{Binding DoItCommand}"/>
  13.     </StackPanel>
  14. </UserControl>

The code behind is nearly empty (except to set the DataContext to the ViewModel.
The .xaml.cs file:
Code - C#: [Select]
  1. using System.Windows.Controls;
  2.  
  3. namespace MVVMUIBindingSample.View
  4. {
  5.     public partial class PaletteTab : UserControl
  6.     {
  7.         public PaletteTab()
  8.         {
  9.             InitializeComponent();
  10.             DataContext = new ViewModel.PaletteTabViewModel();
  11.         }
  12.     }
  13. }

The ViewModel folder contains the PaletteTabViewModel class and two classical helper classes.
PaletteTabViewModel.cs file defines the properties the controls are bound to.
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Windows.Data;
  2. using System.ComponentModel;
  3. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  4.  
  5. namespace MVVMUIBindingSample.ViewModel
  6. {
  7.     class PaletteTabViewModel : ObservableObject
  8.     {
  9.         ICustomTypeDescriptor descriptor;
  10.  
  11.         public PaletteTabViewModel()
  12.         {
  13.             TextStyle = TextStyles.CurrentItem;
  14.             TextStyles.CollectionChanged += (s, e) => TextStyle = TextStyles.CurrentItem;
  15.             DoItCommand = new RelayCommand((_) => DoIt(), (_) => descriptor != null);
  16.         }
  17.  
  18.         public DataItemCollection TextStyles => AcAp.UIBindings.Collections.TextStyles;
  19.  
  20.         public ICustomTypeDescriptor TextStyle
  21.         {
  22.             get { return descriptor; }
  23.             set { descriptor = value; RaisePropertyChanged(nameof(TextStyle)); }
  24.         }
  25.  
  26.         public RelayCommand DoItCommand { get; }
  27.  
  28.         private void DoIt() => AcAp.ShowAlertDialog(((INamedValue)descriptor).Name);
  29.     }
  30. }

The ObservableObject and RelayCommand classes are classical MVVM helpers used to implement the unavoidable INotifyPropertyChanged and ICommand interfaces (minimalist but usually sufficient implementations here).

Observableobject.cs
Code - C#: [Select]
  1. using System.ComponentModel;
  2.  
  3. namespace MVVMUIBindingSample.ViewModel
  4. {
  5.     class ObservableObject : INotifyPropertyChanged
  6.     {
  7.         public event PropertyChangedEventHandler PropertyChanged;
  8.  
  9.         protected void RaisePropertyChanged(string propertyName)
  10.         {
  11.             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  12.         }
  13.     }
  14. }

RelayCommand.cs
Code - C#: [Select]
  1. using System;
  2. using System.Windows.Input;
  3.  
  4. namespace MVVMUIBindingSample.ViewModel
  5. {
  6.     class RelayCommand : ICommand
  7.     {
  8.         readonly Action<object> execute;
  9.         readonly Predicate<object> canExecute;
  10.  
  11.         public RelayCommand(Action<object> execute, Predicate<object> canExecute)
  12.         {
  13.             this.execute = execute;
  14.             this.canExecute = canExecute;
  15.         }
  16.  
  17.         public void Execute(object parameter) => execute(parameter);
  18.  
  19.         public bool CanExecute(object parameter) => canExecute(parameter);
  20.  
  21.         public event EventHandler CanExecuteChanged
  22.         {
  23.             add { CommandManager.RequerySuggested += value; }
  24.             remove { CommandManager.RequerySuggested -= value; }
  25.         }
  26.     }
  27. }
Speaking English as a French Frog

latour_g

  • Newt
  • Posts: 184
Thanks Gile !

Jeff H

  • Needs a day job
  • Posts: 6150
Thanks gile!

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Hi,

Here's a WPF control which does the same as the Styles toolbar (plus the current layer).

the xaml code:
Code - XML: [Select]
  1. <UserControl x:Class="WpfUiBindingSample.AcadStylesControl"
  2.             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.             xmlns:local="clr-namespace:WpfUiBindingSample"
  7.             mc:Ignorable="d"
  8.             d:DesignHeight="270" d:DesignWidth="180">
  9.     <StackPanel Background="WhiteSmoke">
  10.         <Label>Layer:</Label>
  11.         <ComboBox HorizontalAlignment="Stretch" Margin="5,0,5,5"
  12.                  ItemsSource="{Binding Layers}" DisplayMemberPath="Name" SelectedItem="{Binding Clayer}"/>
  13.         <Label>Text Style:</Label>
  14.         <ComboBox HorizontalAlignment="Stretch" Margin="5,0,5,5"
  15.                  ItemsSource="{Binding TextStyles}" DisplayMemberPath="Name" SelectedItem="{Binding Textstyle}"/>
  16.         <Label>Dimension Style:</Label>
  17.         <ComboBox HorizontalAlignment="Stretch" Margin="5,0,5,5"
  18.                  ItemsSource="{Binding DimensionStyles}" DisplayMemberPath="Name" SelectedItem="{Binding Dimstyle}"/>
  19.         <Label>Table Style:</Label>
  20.         <ComboBox HorizontalAlignment="Stretch" Margin="5,0,5,5"
  21.                  ItemsSource="{Binding TableStyles}" DisplayMemberPath="Name" SelectedItem="{Binding Tablestyle}"/>
  22.         <Label>MLeader Style:</Label>
  23.         <ComboBox HorizontalAlignment="Stretch" Margin="5,0,5,10"
  24.                  ItemsSource="{Binding MleaderStyles}" DisplayMemberPath="Name" SelectedItem="{Binding MLeaderstyle}"/>
  25.     </StackPanel>
  26. </UserControl>
  27.  

the xaml.cs code behind:
Code - C#: [Select]
  1. using System.Windows.Controls;
  2.  
  3. namespace WpfUiBindingSample
  4. {
  5.     public partial class AcadStylesControl : UserControl
  6.     {
  7.         public AcadStylesControl()
  8.         {
  9.             InitializeComponent();
  10.             DataContext = new AcadStylesControlViewModel();
  11.         }
  12.     }
  13. }
  14.  

The ViewModel code (all the magic is here)
Some tricks:
- using Reflection allows to refactor the properties initialization in a single private method
- the properties bound to current items have the same name as the Database properties to get/set current styles
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Windows.Data;
  2. using System.ComponentModel;
  3. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  4.  
  5. namespace WpfUiBindingSample
  6. {
  7.     class AcadStylesControlViewModel : INotifyPropertyChanged
  8.     {
  9.         // INotifyPropertyChanged implementation
  10.         public event PropertyChangedEventHandler PropertyChanged;
  11.  
  12.         protected void OnPropertyChanged(string propertyName)
  13.         {
  14.             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  15.         }
  16.  
  17.         // private fields
  18.         ICustomTypeDescriptor layer, textstyle, dimstyle, tablestyle, mleaderstyle;
  19.  
  20.         // constructor (initialization of current style properties)
  21.         public AcadStylesControlViewModel()
  22.         {
  23.             Initialize(nameof(Clayer), Layers);
  24.             Initialize(nameof(Textstyle), TextStyles);
  25.             Initialize(nameof(Dimstyle), DimensionStyles);
  26.             Initialize(nameof(Tablestyle), TableStyles);
  27.             Initialize(nameof(MLeaderstyle), MleaderStyles);
  28.         }
  29.  
  30.         // collection properties bound to AutoCAD via UIBindings
  31.         public DataItemCollection Layers => AcAp.UIBindings.Collections.Layers;
  32.  
  33.         public DataItemCollection TextStyles => AcAp.UIBindings.Collections.TextStyles;
  34.  
  35.         public DataItemCollection DimensionStyles => AcAp.UIBindings.Collections.DimensionStyles;
  36.  
  37.         public DataItemCollection TableStyles => AcAp.UIBindings.Collections.TableStyles;
  38.  
  39.         public DataItemCollection MleaderStyles => AcAp.UIBindings.Collections.MleaderStyles;
  40.  
  41.         // current setting properties (same names as Database properties)
  42.         public ICustomTypeDescriptor Clayer
  43.         {
  44.             get { return layer; }
  45.             set { SetCurrentValue(nameof(Clayer), ref layer, value); }
  46.         }
  47.  
  48.         public ICustomTypeDescriptor Textstyle
  49.         {
  50.             get { return textstyle; }
  51.             set { SetCurrentValue(nameof(Textstyle), ref textstyle, value); }
  52.         }
  53.  
  54.         public ICustomTypeDescriptor Dimstyle
  55.         {
  56.             get { return dimstyle; }
  57.             set { SetCurrentValue(nameof(Dimstyle), ref dimstyle, value); }
  58.         }
  59.  
  60.         public ICustomTypeDescriptor Tablestyle
  61.         {
  62.             get { return tablestyle; }
  63.             set { SetCurrentValue(nameof(Tablestyle), ref tablestyle, value); }
  64.         }
  65.  
  66.         public ICustomTypeDescriptor MLeaderstyle
  67.         {
  68.             get { return mleaderstyle; }
  69.             set { SetCurrentValue(nameof(MLeaderstyle), ref mleaderstyle, value); }
  70.         }
  71.  
  72.         // private methods (using of Reflection to work with properties names)
  73.         private void Initialize(string propName, DataItemCollection collection)
  74.         {
  75.             var curProp = GetType().GetProperty(propName);
  76.             curProp.SetValue(this, collection.CurrentItem, null);
  77.             collection.PropertyChanged += (s, e) =>
  78.             {
  79.                 if (e.PropertyName == nameof(collection.CurrentItem))
  80.                     curProp.SetValue(this, collection.CurrentItem, null);
  81.             };
  82.         }
  83.  
  84.         private void SetCurrentValue(string propName, ref ICustomTypeDescriptor descriptor, ICustomTypeDescriptor value)
  85.         {
  86.             if (value != null && (IDataItem)descriptor != (IDataItem)value)
  87.             {
  88.                 descriptor = value;
  89.                 OnPropertyChanged(propName);
  90.                 var doc = AcAp.DocumentManager.MdiActiveDocument;
  91.                 using (doc.LockDocument())
  92.                 {
  93.                     var db = doc.Database;
  94.                     db.GetType().GetProperty(propName).SetValue(db, ((IDataItem)value).ObjectId, null);
  95.                     doc.Editor.WriteMessage($"\n{propName} = {((INamedValue)value).Name}");
  96.                 }
  97.             }
  98.         }
  99.     }
  100. }
  101.  

A command to show the control in a palette
Code - C#: [Select]
  1. using Autodesk.AutoCAD.Runtime;
  2. using Autodesk.AutoCAD.Windows;
  3. using System;
  4. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  5.  
  6. [assembly: CommandClass(typeof(WpfUiBindingSample.Commands))]
  7.  
  8. namespace WpfUiBindingSample
  9. {
  10.     public class Commands
  11.     {
  12.         static PaletteSet palette;
  13.         static bool wasVisible;
  14.  
  15.         [CommandMethod("STYLES")]
  16.         public static void TestPaletteCommand()
  17.         {
  18.             if (palette == null)
  19.             {
  20.                 palette = new PaletteSet("Layer & Styles", "STYLES", new Guid("{3F1BEBD1-3005-412F-8D02-E6475EF5364F}"));
  21.                 palette.Style =
  22.                     PaletteSetStyles.ShowAutoHideButton |
  23.                     PaletteSetStyles.ShowCloseButton |
  24.                     PaletteSetStyles.ShowPropertiesMenu;
  25.                 palette.MinimumSize = new System.Drawing.Size(180, 275);
  26.                 palette.AddVisual("Styles", new AcadStylesControl());
  27.  
  28.                 var docs = AcAp.DocumentManager;
  29.                 docs.DocumentBecameCurrent += (s, e) => palette.Visible = e.Document == null ? false : wasVisible;
  30.                 docs.DocumentCreated += (s, e) => palette.Visible = wasVisible;
  31.                 docs.DocumentToBeDeactivated += (s, e) => wasVisible = palette.Visible;
  32.                 docs.DocumentToBeDestroyed += (s, e) =>
  33.                 {
  34.                     wasVisible = palette.Visible;
  35.                     if (docs.Count == 1)
  36.                         palette.Visible = false;
  37.                 };
  38.             }
  39.             palette.Visible = true;
  40.         }
  41.     }
  42. }
  43.  
« Last Edit: July 26, 2016, 11:40:39 AM by gile »
Speaking English as a French Frog