Author Topic: create an AutoCAD Table from Palette WPF MVVM  (Read 2579 times)

0 Members and 1 Guest are viewing this topic.

HOSNEYALAA

  • Newt
  • Posts: 103
create an AutoCAD Table from Palette WPF MVVM
« on: June 12, 2023, 08:13:45 AM »
HI ALL
HI @gile

Original topic here
https://www.theswamp.org/index.php?topic=31864.15
from notes gile
Quote
But if you want to keep on the WPF MVVM Bindings route, you should bind your button to a property of the ViewModel which type implements ICommand instead of handling the Button_Click event (as shown in this example) and you would not relay on the View (the ListView items) to fill the table but simply use the Selection property of the ViewModel which contains the data you need.
Try to apply it though There is an error that I do not understand

Code - XML: [Select]
  1. <UserControl x:Class="ObservableSelectionSample.SelectionView"
  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:ObservableSelectionSample"
  7.                 mc:Ignorable="d"
  8.                 d:DesignHeight="190" d:DesignWidth="220">
  9.     <Grid Background="WhiteSmoke">
  10.         <Grid.RowDefinitions>
  11.             <RowDefinition Height="Auto" />
  12.             <RowDefinition />
  13.         </Grid.RowDefinitions>
  14.         <StackPanel Grid.Row="0" Margin="5,5,101,5"  Orientation="Horizontal">
  15.             <TextBlock Margin="15,0,5,0">Total =</TextBlock>
  16.             <TextBlock Text="{Binding Total, StringFormat={}{0:0.00}}" />
  17.         </StackPanel>
  18.         <ListView Grid.Row="1" Margin="5" ItemsSource="{Binding Selection}">
  19.             <ListView.ItemContainerStyle>
  20.                 <Style TargetType="ListViewItem">
  21.                     <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  22.                 </Style>
  23.             </ListView.ItemContainerStyle>
  24.             <ListView.View>
  25.                 <GridView>
  26.                     <GridViewColumn Header="Type" Width="80" DisplayMemberBinding="{Binding Name}" />
  27.                     <GridViewColumn Header="Qty" Width="40">
  28.                         <GridViewColumn.CellTemplate>
  29.                             <DataTemplate>
  30.                                 <TextBlock HorizontalAlignment="Right" Text="{Binding Count}" />
  31.                             </DataTemplate>
  32.                         </GridViewColumn.CellTemplate>
  33.                     </GridViewColumn>
  34.                     <GridViewColumn Header="Length" Width="80">
  35.                         <GridViewColumn.CellTemplate>
  36.                             <DataTemplate>
  37.                                 <TextBlock HorizontalAlignment="Right" Text="{Binding Length, StringFormat={}{0:0.00}}" />
  38.                             </DataTemplate>
  39.                         </GridViewColumn.CellTemplate>
  40.                     </GridViewColumn>
  41.                 </GridView>
  42.             </ListView.View>
  43.         </ListView>
  44.         <Button Content="table" HorizontalAlignment="Left" Margin="163,3,0,0" VerticalAlignment="Top" Width="41" Height="21" Command="{Binding  }" />
  45.     </Grid>
  46. </UserControl>
  47.      
  48.  

Code - C#: [Select]
  1.  
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.Windows.Data;
  6.  
  7. using System.Collections.ObjectModel;
  8. using System.ComponentModel;
  9. using System.Linq;
  10. using Autodesk.AutoCAD.EditorInput;
  11. using Autodesk.AutoCAD.Geometry;
  12.  
  13.  
  14. using System;
  15. using System.IO;
  16. using System.Text;
  17.  
  18. using System.Collections;
  19. using System.Collections.Generic;
  20. using System.Runtime.InteropServices;
  21.  
  22. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  23. namespace ObservableSelectionSample
  24. {
  25.     public class SelectionViewModel : INotifyPropertyChanged
  26.     {
  27.         #region INotifyPropertyChanged implementation
  28.         public event PropertyChangedEventHandler PropertyChanged;
  29.  
  30.         protected void NotifyPropertyChanged(string propertyName) =>
  31.             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  32.         #endregion
  33.  
  34.         // Type of item of the ObsevableCollection.
  35.         public struct CurveGroup
  36.         {
  37.             // Properties bound to the ListView columns
  38.             public int Count { get; set; }
  39.             public double Length { get; set; }
  40.             public string Name { get; set; }
  41.         }
  42.  
  43.         DataItemCollection itemCollection;
  44.         double total;
  45.  
  46.         // Property bound to the ListView
  47.         public ObservableCollection<CurveGroup> Selection { get; }
  48.  
  49.         // Property bound to the TextBlock
  50.         public double Total
  51.         {
  52.             get { return total; }
  53.             set { total = value; NotifyPropertyChanged(nameof(Total)); }
  54.         }
  55.  
  56.         // Initialization and subscription to CollectionChanged and ItemsChanged events of the itemCollection
  57.         public SelectionViewModel()
  58.         {
  59.             Selection = new ObservableCollection<CurveGroup>();
  60.             itemCollection = Application.UIBindings.Collections.Selection;
  61.             itemCollection.CollectionChanged += (s, e) => Update();
  62.             itemCollection.ItemsChanged += (s, e) => Update();
  63.         }
  64.  
  65.         // Updating Selection and Total properties.
  66.         private void Update()
  67.         {
  68.             bool IsValidCurve(RXClass rXClass) =>
  69.                 rXClass.IsDerivedFrom(RXObject.GetClass(typeof(Curve))) &&
  70.                 rXClass.DxfName != "RAY" && rXClass.DxfName != "XLINE";
  71.             Selection.Clear();
  72.             using (var tr = new OpenCloseTransaction())
  73.             {
  74.                 var groups = itemCollection
  75.                     .Cast<IDataItem>()
  76.                     .Where(item => IsValidCurve(item.ObjectId.ObjectClass))
  77.                     .Select(item => (Curve)tr.GetObject(item.ObjectId, OpenMode.ForRead))
  78.                     .GroupBy(curve => curve.GetType().Name)
  79.                     .Select(group => new CurveGroup
  80.                     {
  81.                         Count = group.Count(),
  82.                         Length = group.Sum(c => c.GetDistanceAtParameter(c.EndParam)),
  83.                         Name = group.Key
  84.                     });
  85.                 foreach (var group in groups)
  86.                     Selection.Add(group);
  87.                 Total = Selection.Sum(x => x.Length);
  88.             }
  89.         }
  90.  
  91.         string txtRad;
  92.  
  93.         /// <summary>
  94.         /// Gets the Command object bound to the Radius button (>).
  95.         /// </summary>
  96.         public RelayCommand RadiusCommandz => new RelayCommand((_) => Gettable(), (_) => true);
  97.  
  98.         /// <summary>
  99.         /// Method called by GetRadiusCommand.
  100.         /// </summary>
  101.         private void Gettable()
  102.         {
  103.             //-----------------------------  insert table  -------------------------------------//
  104.             var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
  105.  
  106.             PromptPointOptions ppo = new PromptPointOptions("\nPick insertion point of table: ");
  107.  
  108.             PromptPointResult pres = ed.GetPoint(ppo);
  109.  
  110.             if (pres.Status != PromptStatus.OK) return;
  111.  
  112.             Point3d inspt = pres.Value;
  113.  
  114.             // CreateTable(table, inspt);
  115.         }
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.         //--------------------------------------------------------------------------------------------//
  125.         public static void CreateTable(List<List<string>> tabledata, Point3d insPt)
  126.         {
  127.             // completely borrowed from Kean Walmsley here:
  128.             // http://through-the-interface.typepad.com/through_the_interface/2011/11/handling-protocol-changes-to-autocads-table-in-net.html
  129.  
  130.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  131.  
  132.             Database db = doc.Database;
  133.  
  134.             string ver = ((string)Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("acadver")).Substring(0, 2);
  135.  
  136.             int acver = Convert.ToInt32(ver);
  137.  
  138.             Transaction tr = doc.TransactionManager.StartTransaction();
  139.  
  140.             using (tr)
  141.             {
  142.                 // Set some constants that we'll use to create our tables
  143.  
  144.                 int numRows = tabledata.Count;
  145.  
  146.                 int numCols = tabledata.ElementAt(1).Count;
  147.  
  148.                 double txtHeight = db.Textsize;
  149.  
  150.                 double rowHeight = txtHeight * 1.7;
  151.  
  152.                 double colWidth = txtHeight * 30;
  153.  
  154.                 double horMarg = rowHeight / 6;
  155.  
  156.                 double verMarg = rowHeight / 4;
  157.  
  158.                 // We'll add our tables to the current space
  159.  
  160.                 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  161.  
  162.                 // We'll use scoping to let us use the same variable
  163.  
  164.                 // name(s) for both tables we're creating
  165.  
  166.                 // for A2009
  167.  
  168.                 if (acver == 17)
  169.                 {
  170.  
  171.                     // Create a table with the old protocol
  172.  
  173.                     Table tb = new Table();
  174.  
  175.                     tb.TableStyle = db.Tablestyle;
  176.  
  177.                     // Resize the table, adding rows and columns
  178.  
  179.                     tb.NumRows = numRows;
  180.  
  181.                     tb.NumColumns = numCols;
  182.  
  183.                     // Set the column width and row height
  184.  
  185.                     tb.SetColumnWidth(colWidth);
  186.  
  187.                     tb.SetRowHeight(rowHeight);
  188.  
  189.                     // Set the horizontal and vertical margins
  190.  
  191.                     tb.HorizontalCellMargin = horMarg;
  192.  
  193.                     tb.VerticalCellMargin = verMarg;
  194.  
  195.                     // Make sure the header and title rows are visible
  196.  
  197.                     tb.IsHeaderSuppressed = false;
  198.  
  199.                     tb.IsTitleSuppressed = false;
  200.  
  201.                     // Set the title string
  202.  
  203.                     tb.SetTextString(0, 0, tabledata.ElementAt(0)[0]);
  204.  
  205.                     // Set the text height for the full table: value of 7
  206.  
  207.                     // is bit-encoded Data (1), Title (2) and Header (4)
  208.  
  209.                     tb.SetTextHeight(txtHeight, 7);
  210.  
  211.                     // Populate the contents of the header and data sections
  212.  
  213.                     for (int i = 1; i < numRows; i++)
  214.                     {
  215.  
  216.                         for (int j = 0; j < numCols; j++)
  217.                         {
  218.  
  219.                             // Contents is A-E for the header an 0-n for the data
  220.  
  221.                             tb.SetTextString(i, j, tabledata.ElementAt(i - 1)[j]);
  222.  
  223.                         }
  224.  
  225.                     }
  226.  
  227.                     tb.GenerateLayout();
  228.  
  229.                     tb.Position = insPt;
  230.  
  231.                     btr.AppendEntity(tb);
  232.  
  233.                     tr.AddNewlyCreatedDBObject(tb, true);
  234.  
  235.                 }
  236.                 // for A2010 >
  237.                 else
  238.                     if (acver == 18)
  239.                 {
  240.  
  241.                     // Create a table with the new protocol
  242.  
  243.                     Table tb = new Table();
  244.  
  245.                     tb.TableStyle = db.Tablestyle;
  246.  
  247.                     // Set the height and width of the initial row and
  248.  
  249.                     // column belonging by default to the blank Table
  250.  
  251.                     tb.Rows[0].Height = rowHeight;
  252.  
  253.                     tb.Columns[0].Width = colWidth;
  254.  
  255.                     // Add the remaining rows and columns
  256.  
  257.                     tb.InsertRows(1, rowHeight, numRows - 1);
  258.  
  259.                     tb.InsertColumns(1, colWidth, numCols - 1);
  260.  
  261.                     // To query the number of rows and columns...
  262.  
  263.                     //
  264.  
  265.                     // int nRows = tb.Rows.Count;
  266.  
  267.                     // int nCols = tb.Columns.Count;
  268.  
  269.                     // To "suppress" the title and header, find the row
  270.  
  271.                     // with a style of "Title" or "Header" and set it to ""
  272.  
  273.                     tb.Cells[0, -1].Style = "Title";
  274.  
  275.                     tb.Cells[1, -1].Style = "Header";
  276.  
  277.                     // Add the contents of the Title cell
  278.  
  279.                     Cell tc = tb.Cells[0, 0];
  280.  
  281.                     tc.Contents.Add();
  282.  
  283.                     tc.Contents[0].TextHeight = txtHeight;
  284.  
  285.                     tc.Contents[0].TextString = tabledata.ElementAt(0)[0];
  286.  
  287.                     // Populate the contents of the header and data sections
  288.  
  289.                     for (int i = 1; i < numRows; i++)
  290.                     {
  291.  
  292.                         for (int j = 0; j < numCols; j++)
  293.                         {
  294.  
  295.                             // Contents is A-E for the header an 0-n for the data
  296.  
  297.                             string contents = tabledata.ElementAt(i)[j];
  298.  
  299.  
  300.                             Cell c = tb.Cells[i, j];
  301.  
  302.                             // Set the text contents of the cell
  303.  
  304.                             c.Contents.Add();
  305.  
  306.                             c.Contents[0].TextHeight = txtHeight;
  307.  
  308.                             c.Contents[0].TextString = contents;
  309.  
  310.                             // Set the horizontal margins
  311.  
  312.                             c.Borders.Left.Margin = horMarg;
  313.  
  314.                             c.Borders.Right.Margin = horMarg;
  315.  
  316.                             // Set the vertical margins
  317.  
  318.                             c.Borders.Top.Margin = verMarg;
  319.  
  320.                             c.Borders.Bottom.Margin = verMarg;
  321.  
  322.                         }
  323.  
  324.                     }
  325.  
  326.                     // We'll separate this table from the first one
  327.  
  328.                     tb.Position = insPt;
  329.  
  330.                     tb.GenerateLayout();
  331.  
  332.                     btr.AppendEntity(tb);
  333.  
  334.                     tr.AddNewlyCreatedDBObject(tb, true);
  335.  
  336.                 }
  337.  
  338.                 tr.Commit();
  339.  
  340.             }
  341.  
  342.         }
  343.  
  344.         //--------------------------------------------------------------------------------------------//
  345.  
  346.  
  347.  
  348.  
  349.     }
  350. }
  351.  
  352.  
  353.  


Code - C#: [Select]
  1. using System;
  2. using System.Windows.Input;
  3.  
  4. namespace ObservableSelectionSample
  5. {
  6.     /// <summary>
  7.     /// Provides a type implementing ICommand
  8.     /// </summary>
  9.     class RelayCommand : ICommand
  10.     {
  11.         readonly Action<object> execute;
  12.         readonly Predicate<object> canExecute;
  13.  
  14.         /// <summary>
  15.         /// Creates a new instance of RelayCommand.
  16.         /// </summary>
  17.         /// <param name="execute">Action to execute.</param>
  18.         /// <param name="canExecute">Predicate indicating if the action can be executed.</param>
  19.         public RelayCommand(Action<object> execute, Predicate<object> canExecute)
  20.         {
  21.             this.execute = execute;
  22.             this.canExecute = canExecute;
  23.         }
  24.  
  25.         /// <summary>
  26.         /// Executes the action passed as parameter to the constructor.
  27.         /// </summary>
  28.         /// <param name="parameter">Action parameter (may be null).</param>
  29.         public void Execute(object parameter) => execute(parameter);
  30.  
  31.         /// <summary>
  32.         /// Executes the predicate passed as parameter to the constructor.
  33.         /// </summary>
  34.         /// <param name="parameter">Predicate parameter (may be null).</param>
  35.         /// <returns>Result of the predictae execution.</returns>
  36.         public bool CanExecute(object parameter) => canExecute(parameter);
  37.  
  38.         /// <summary>
  39.         /// Event indicating that the returned value of the predicte changed.
  40.         /// </summary>
  41.         public event EventHandler CanExecuteChanged
  42.         {
  43.             add { CommandManager.RequerySuggested += value; }
  44.             remove { CommandManager.RequerySuggested -= value; }
  45.         }
  46.     }
  47. }
  48.  


Please help, thank you

edited code tags to suit code type : kdub
« Last Edit: June 12, 2023, 05:22:06 PM by kdub_nz »

HOSNEYALAA

  • Newt
  • Posts: 103
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #1 on: June 12, 2023, 08:16:29 AM »
Images

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #2 on: June 12, 2023, 10:31:11 AM »
in the XAML, you should use a Grid instead of a StackPanel so that the button will be anchored to the right of the control.
You should also explicitly Bind it to the 'RadiusCommandz' (and choose self explanatory member names...)
Code - XML: [Select]
  1. <UserControl x:Class="ObservableSelectionSample.SelectionView"
  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:ObservableSelectionSample"
  7.             mc:Ignorable="d"
  8.             d:DesignHeight="150" d:DesignWidth="220">
  9.     <Grid Background="WhiteSmoke">
  10.         <Grid.RowDefinitions>
  11.             <RowDefinition Height="Auto" />
  12.             <RowDefinition />
  13.             <RowDefinition Height="Auto" />
  14.         </Grid.RowDefinitions>
  15.         <Grid>
  16.             <Grid.ColumnDefinitions>
  17.                 <ColumnDefinition Width="Auto"/>
  18.                 <ColumnDefinition Width="*"/>
  19.                 <ColumnDefinition Width="Auto"/>
  20.             </Grid.ColumnDefinitions>
  21.             <TextBlock Grid.Column="0" Margin="15,0,5,0" VerticalAlignment="Center">Total =</TextBlock>
  22.             <TextBlock Grid.Column="1" VerticalAlignment="Center" Text="{Binding Total, StringFormat={}{0:0.00}}" />
  23.             <Button Grid.Column="2" Content="table" HorizontalAlignment="Center"  Margin="5"
  24.                Width="41" Height="21" Command="{Binding  RadiusCommandz}" />
  25.         </Grid>
  26.         <ListView Grid.Row="1" Margin="5" ItemsSource="{Binding Selection}">
  27.             <ListView.ItemContainerStyle>
  28.                 <Style TargetType="ListViewItem">
  29.                     <Setter Property="HorizontalContentAlignment" Value="Stretch" />
  30.                 </Style>
  31.             </ListView.ItemContainerStyle>
  32.             <ListView.View>
  33.                 <GridView>
  34.                     <GridViewColumn Header="Type" Width="80" DisplayMemberBinding="{Binding Type.Name}" />
  35.                     <GridViewColumn Header="Qty" Width="40">
  36.                         <GridViewColumn.CellTemplate>
  37.                             <DataTemplate>
  38.                                 <TextBlock HorizontalAlignment="Right" Text="{Binding Count}" />
  39.                             </DataTemplate>
  40.                         </GridViewColumn.CellTemplate>
  41.                     </GridViewColumn>
  42.                     <GridViewColumn Header="Length" Width="80">
  43.                         <GridViewColumn.CellTemplate>
  44.                             <DataTemplate>
  45.                                 <TextBlock HorizontalAlignment="Right" Text="{Binding Length, StringFormat={}{0:0.00}}" />
  46.                             </DataTemplate>
  47.                         </GridViewColumn.CellTemplate>
  48.                     </GridViewColumn>
  49.                 </GridView>
  50.             </ListView.View>
  51.         </ListView>
  52.     </Grid>
  53. </UserControl>
  54.  
You can also, in a first time, define the bound command with a simple task to test if it works.
Code - C#: [Select]
  1.         /// <summary>
  2.         /// Gets the Command object bound to the Radius button (>).
  3.         /// </summary>
  4.         public RelayCommand RadiusCommandz => new RelayCommand((_) => Gettable(), (_) => true);
  5.  
  6.         /// <summary>
  7.         /// Method called by GetRadiusCommand.
  8.         /// </summary>
  9.         private void Gettable()
  10.         {
  11.             Application.ShowAlertDialog($"Total length: {Total:0.00}");
  12.         }
Speaking English as a French Frog

HOSNEYALAA

  • Newt
  • Posts: 103
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #3 on: June 13, 2023, 01:30:53 AM »

Thanks @gile
to answer and explain

But I have an error that I don't understand
Is it possible You look what my problem

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #4 on: June 13, 2023, 02:40:10 AM »
What don't you understand about: "Property type 'RelayCommand' is less accessible than 'SelectionViewModel.RadiusCommandz'"?

'SelectionViewModel.RadiusCommandz' is public and 'class RelayCommand' is internal (default).
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #5 on: June 13, 2023, 02:59:00 AM »
@HOSNEYALAA
If you want to learn, don't copy and paste code snippets. Write the code yourself, trying to understand what you're typing and making it your own with your own style of naming.
Speaking English as a French Frog

HOSNEYALAA

  • Newt
  • Posts: 103
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #6 on: June 13, 2023, 05:32:51 AM »
Thank you very much gile

I don't have enough experience
And I learn from your examples

I lack a lot of experience
They cried because of language and lack of time

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #7 on: June 13, 2023, 07:12:04 AM »
The RelayCommand class have to be public to avoid "Property type 'RelayCommand' is less accessible than 'SelectionViewModel.RadiusCommandz'", but within this class, the 'execute' and 'canExecute' fields should be [private] readonly to comply with encapsulation.

Before learning WPF, you need to be comfortable with the basics of Object-Oriented Programming.
« Last Edit: June 13, 2023, 07:24:06 AM by gile »
Speaking English as a French Frog

HOSNEYALAA

  • Newt
  • Posts: 103
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #8 on: June 13, 2023, 10:58:29 AM »
Thank you
 For the support you give us
 I like your code by wpf I can work Lisp does this
But there is no such dynamic in the selection
 I wanted to add a button to make a table

Thanks

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2140
  • class keyThumper<T>:ILazy<T>
Re: create an AutoCAD Table from Palette WPF MVVM
« Reply #9 on: June 13, 2023, 08:50:17 PM »
@HOSNEYALAA
If you want to learn, don't copy and paste code snippets. Write the code yourself, trying to understand what you're typing and making it your own with your own style of naming.

:)

I re-learn this advice at least 13 times a year.
. . . it also helps to focus the mind.
Particularly applicable when playing with a 'new' language or switching languages for a while.
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.