Autocad API.. Data bindinding does not work

Autocad API.. Data bindinding does not work

Anonymous
Not applicable
1,211 Views
5 Replies
Message 1 of 6

Autocad API.. Data bindinding does not work

Anonymous
Not applicable

I am trying from several days to try to make it work but I could not.. Please help.

 

My xaml

 

<UserControl x:Class="PN_NO"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
>
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:SchneiderMacros"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">

<UserControl.DataContext >
 <local:mainviewmodel ></local:mainviewmodel>
</UserControl.DataContext>
<Grid Background="#FF2D2D30">
<StackPanel >
<TextBox Height=" 30" Text="{Binding device}" Margin=" 10"></TextBox>
 </StackPanel>

</Grid> </UserControl>

 

 

My view class

 

Public Class PNWPFPalette

Public devicelocaton As String
Shared _PS1 As PaletteSet = Nothing
Public Sub ShowPNWPFPalette()

If _PS1 Is Nothing Then
_PS1 = New PaletteSet("Modify Attributes")
_PS1.Size = New Size(400, 600)
_PS1.DockEnabled = DirectCast(CInt(DockSides.Left) + CInt(DockSides.Right), DockSides)
Dim uc1 As New PN_NO
'_PS1.AddVisual("Update PN", uc1)
Dim host As ElementHost = New ElementHost
host.AutoSize = True
host.Dock = DockStyle.Fill
host.Child = uc1
_PS1.Add("Modify PN", host)
Dim uc2 As New PN_NO
Dim host1 As ElementHost = New ElementHost
host1.AutoSize = True
host1.Dock = DockStyle.Fill
host1.Child = uc2
_PS1.Add("Modify PN2", host1)
End If
_PS1.KeepFocus = True
_PS1.Visible = True
End Sub


Public Function findattributes()
Dim DL as string = "Pankaj"
Return DL
End Function

End Class

 

 

My Viewmodel class

 

Public Class mainviewmodel
Implements INotifyPropertyChanged

Public Property device As String
Get
Return _device
End Get
Set(value As String)
_device = value
OnPropertyChange("device")
End Set
End Property
Private _device As String
Protected Sub OnPropertyChange(name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
End Class

 

 

Class where I am running my commands 

 

Public class mycommands

 

<CommandMethod("addPNPalette", CommandFlags.UsePickSet)>
Public Sub PNPalette()
Dim addpn As New PNWPFPalette
Dim viewmodel As New mainviewmodel
addpn.ShowPNWPFPalette()
Dim DL As String = addpn.findattributes()

viewmodel.device = "Schneider"
End Sub

End Class

 

 

Afte running command textbox remains blank... Please help.......

0 Likes
Accepted solutions (1)
1,212 Views
5 Replies
Replies (5)
Message 2 of 6

_gile
Consultant
Consultant

Hi,

 

When you set the DataContext of the UserControl to MainViewModel, you implictely create a new instance of MainViewModel class:

 

<UserControl.DataContext >
     <local:MainViewModel />
</UserControl.DataContext>

in PN_NO.xaml is the same as the following PN_NO constructor code  in PN_NO.xaml.vb:

 

Public Sub New()
InitializeComponent() DataContext = New MainViewModel() End Sub

So creating a new instance of  MainViewModel in the CommandMethod and setting this instance Device property has no effect on the instance bound to the UserControl.

 

 

PS: please use the {i} button to insert code so that if keeps formatted.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 6

Anonymous
Not applicable

@_gile, thnaks for reply.

 

But I did not understood, what I need to change then?

0 Likes
Message 4 of 6

_gile
Consultant
Consultant

Hi,

 

I do not know what you're trying to do but it looks like you want to implement MVVM design pattern.

In MVVM, the View only interacts with the ViewModel so the simplest way is to set the Device property default value in the MainViewModel constructor:

 

Public Class MainViewModel
Implements InotitfyPropertyChanged

Public Sub New() Me.Device = "Schneider" End Sub

,...
End Class

If you need to get the Device value from elsewhere (i.e. the Mode partl), you need to make it accessible from the Model to the ViewModel.

Typically the ViewModel creates an instance of Model class and get the data from a property of this instance. If the data may change, the Model may raise some events to notify the changes to the ViewModel.

But this seems to be useless complexification for a such simple task...

 

Some links about MVVM:

https://msdn.microsoft.com/en-us/library/hh848246.aspx

https://msdn.microsoft.com/en-us/library/ff798384.aspx



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 6

Anonymous
Not applicable

@_gile thanks for reply to my novice question!

 

In that case I need to implement property change event in Model and view model both?

 

Can you give example of getting data from model and notifying it to UI element in View?

 

 

0 Likes
Message 6 of 6

_gile
Consultant
Consultant
Accepted solution

As I said implementing MVVM can make things complicated especially with a modeless palette that requires managing the activation and creation of new documents.
Here is a small example (C#, sorry I don't use VB) that shows the current layer in the palette. Model, View and ViewModel are separated into different namespaces.

 

The View part:

XAML

<UserControl x:Class="AcadWpfPalette.View.PaletteTab"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:AcadWpfPalette.View"
             xmlns:viewModel="clr-namespace:AcadWpfPalette.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <viewModel:SampleViewModel/>
    </UserControl.DataContext>
    <StackPanel Background="WhiteSmoke">
        <Label Margin="5">Current layer:</Label>
        <TextBlock Margin="5" Height="30" Text="{Binding Clayer}"/>
    </StackPanel>
</UserControl>

C# code for the Palette

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Windows;
using System;

namespace AcadWpfPalette.View
{
    class SamplePalette
    {
        static PaletteSet palette;
        static bool wasVisible;

        public void Show()
        {
            if (palette == null)
            {
                palette = new PaletteSet("SamplePalette", new Guid("{3E405DB6-AA46-4512-B91C-F7914B1440CF}"));
                palette.Style =
                    PaletteSetStyles.ShowAutoHideButton |
                    PaletteSetStyles.ShowCloseButton |
                    PaletteSetStyles.ShowPropertiesMenu;
                palette.MinimumSize = new System.Drawing.Size(200, 240);
                palette.Name = "Sample Palette";
                palette.AddVisual("Sample Control", new PaletteTab());

                // auto hiding on no document state
                var docs = Application.DocumentManager;
                docs.DocumentBecameCurrent += (s, e) => palette.Visible = e.Document == null ? false : wasVisible;
                docs.DocumentCreated += (s, e) => palette.Visible = wasVisible;
                docs.DocumentToBeDeactivated += (s, e) => wasVisible = palette.Visible;
                docs.DocumentToBeDestroyed += (s, e) =>
                {
                    wasVisible = palette.Visible;
                    if (docs.Count == 1) palette.Visible = false;
                };
            }
            palette.Visible = true;
        }
    }
}

 

The ViewModel part:

using AcadWpfPalette.Model;
using System.ComponentModel;

namespace AcadWpfPalette.ViewModel
{
    class SampleViewModel : INotifyPropertyChanged
    {
        string clayer;
        AcadModel model;

        public SampleViewModel()
        {
            model = new AcadModel();
            clayer = model.Clayer;
            model.CurrentLayerChanged += Model_CurrentLayerChanged;
        }

        public string Clayer
        {
            get { return clayer; }
            set
            {
                clayer = value;
                RaisePropertyChanged("Clayer");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        private void Model_CurrentLayerChanged(object sender, CurrentLayerChangedEventArgs e)
        {
            Clayer = e.Clayer;
        }
    }
}

 

The Model part:

using Autodesk.AutoCAD.ApplicationServices;
using System;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
using AcDb = Autodesk.AutoCAD.DatabaseServices;

namespace AcadWpfPalette.Model
{
    public class AcadModel
    {
        DocumentCollection docs;
        string clayer;

        public AcadModel()
        {
            clayer = (string)AcAp.GetSystemVariable("CLAYER");
            docs = AcAp.DocumentManager;
            foreach (Document doc in docs)
            {
                docs.MdiActiveDocument.Database.SystemVariableChanged += Database_SystemVariableChanged;
            }
            docs.DocumentCreated += Docs_DocumentCreated;
            docs.DocumentActivated += Docs_DocumentActivated;
        }

        public string Clayer
        {
            get { return clayer; }
            private set { clayer = value; }
        }

        public delegate void CurrentLayerChangedEventHandler(object sender, CurrentLayerChangedEventArgs e);

        public event CurrentLayerChangedEventHandler CurrentLayerChanged;

        private void Docs_DocumentActivated(object sender, DocumentCollectionEventArgs e)
        {
            Clayer = (string)AcAp.GetSystemVariable("CLAYER");
            RaiseCurrentLayerChanged();
        }

        private void Docs_DocumentCreated(object sender, DocumentCollectionEventArgs e)
        {
            e.Document.Database.SystemVariableChanged += Database_SystemVariableChanged;
            RaiseCurrentLayerChanged();
        }

        private void Database_SystemVariableChanged(object sender, AcDb.SystemVariableChangedEventArgs e)
        {
            if (e.Name == "CLAYER")
            {
                Clayer = (string)AcAp.GetSystemVariable("CLAYER");
                RaiseCurrentLayerChanged();
            }
        }

        private void RaiseCurrentLayerChanged()
        {
            CurrentLayerChangedEventHandler handler = CurrentLayerChanged;
            if (handler != null)
                handler(this, new CurrentLayerChangedEventArgs(Clayer));
        }
    }

    public class CurrentLayerChangedEventArgs : EventArgs
    {
        public string Clayer { get; }
        public CurrentLayerChangedEventArgs(string clayer) { Clayer = clayer; }
    }
}

 

The Command to show the Palette:

using Autodesk.AutoCAD.Runtime;

[assembly: CommandClass(typeof(AcadWpfPalette.Commands))]

namespace AcadWpfPalette
{
    public class Commands
    {
        [CommandMethod("CMD")]
        public void Cmd()
        {
            View.SamplePalette palette = new View.SamplePalette();
            palette.Show();
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes