Hi,
Another minimalist sample using a Palette (modeless) with a Wpf control and MVVM design pattern.

Model part (AutoCAD related stuf)
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Internal;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace XDataPaletteSample.Model
{
class AcadWorker
{
private static ObjectId _id;
private const string _appName = "SomeApp";
public static string GetXData()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
Utils.SetFocusToDwgView();
var result = ed.GetEntity("\nSelect Object: ");
if (result.Status != PromptStatus.OK)
return null;
_id = result.ObjectId;
using (var tr = db.TransactionManager.StartOpenCloseTransaction())
{
var ent = (Entity)tr.GetObject(_id, OpenMode.ForRead);
var resbuf = ent.GetXDataForApplication(_appName);
if (resbuf == null)
return "";
return resbuf.AsArray()[1].Value.ToString();
}
}
public static void SetXData(string data)
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
using (doc.LockDocument())
using (var tr = db.TransactionManager.StartTransaction())
{
var regAppTable = (RegAppTable)tr.GetObject(db.RegAppTableId, OpenMode.ForRead);
if (!regAppTable.Has(_appName))
{
regAppTable.UpgradeOpen();
var regApp = new RegAppTableRecord();
regApp.Name = _appName;
regAppTable.Add(regApp);
tr.AddNewlyCreatedDBObject(regApp, true);
}
var resbuf = string.IsNullOrEmpty(data) ?
new ResultBuffer(new TypedValue(1001, _appName)) :
new ResultBuffer(new TypedValue(1001, _appName), new TypedValue(1000, data));
var ent = tr.GetObject(_id, OpenMode.ForWrite);
ent.XData = resbuf;
tr.Commit();
}
}
}
}
View part
The xaml file:
<UserControl x:Class="XDataPaletteSample.View.XDataControl"
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:ViewModel="clr-namespace:XDataPaletteSample.ViewModel"
mc:Ignorable="d"
d:DesignHeight="135" d:DesignWidth="300">
<UserControl.DataContext>
<ViewModel:MainViewModel/>
</UserControl.DataContext>
<Grid Background="WhiteSmoke">
<StackPanel>
<Button Width="100" Content="Select Object" Margin="10" Command="{Binding SelectCommand}"/>
<StackPanel Orientation="Horizontal" Margin="10">
<Label Content="Value: " Margin="0,0,5,0"/>
<TextBox Height="20" Width="225" Text="{Binding DataValue}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="10" HorizontalAlignment="Center">
<Button Width="75" Margin="0,0,10,0" Content="Write data" IsEnabled="{Binding Enabled}" Command="{Binding WriteDataCommand}"/>
<Button Width="75" Margin="10,0,0,0" Content="Cancel" IsEnabled="{Binding Enabled}" Command="{Binding CancelCommand}"/>
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
the code behind:
using System.Windows.Controls;
namespace XDataPaletteSample.View
{
public partial class XDataControl : UserControl
{
public XDataControl()
{
InitializeComponent();
}
}
}
ViewModel part (including the classical ObservableObject and RelayCommand helpers)
using System.ComponentModel;
namespace XDataPaletteSample.ViewModel
{
class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
using System;
using System.Windows.Input;
namespace XDataPaletteSample.ViewModel
{
class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action execute)
: this((_) => execute()) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute ?? ((_) => true);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
using System;
using System.Windows.Input;
using XDataPaletteSample.Model;
namespace XDataPaletteSample.ViewModel
{
class MainViewModel : ObservableObject
{
private string _dataValue;
public string DataValue
{
get { return _dataValue; }
set
{
_dataValue = value;
this.Enabled = _dataValue != null;
RaisePropertyChanged("DataValue");
RaisePropertyChanged("Enabled");
}
}
public bool Enabled { get; set; }
public ICommand SelectCommand
{
get { return new RelayCommand(() => this.DataValue = AcadWorker.GetXData()); }
}
public ICommand WriteDataCommand
{
get
{
return new RelayCommand(
() => { AcadWorker.SetXData(this.DataValue); this.DataValue = null; });
}
}
public ICommand CancelCommand
{
get { return new RelayCommand(() => this.DataValue = null); }
}
}
}
And the command to display the palette
using System;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
[assembly: CommandClass(typeof(XDataPaletteSample.CommandMethods))]
namespace XDataPaletteSample
{
public class CommandMethods
{
private static PaletteSet _palette;
[CommandMethod("XDATAPALETTE")]
public static void XDataPaletteCommand()
{
if (_palette == null)
{
_palette = new PaletteSet("XDataPalette", new Guid("{2E9CEAF7-5CFB-4B5D-A2B9-B8BB215DB604}"));
_palette.Style =
PaletteSetStyles.ShowAutoHideButton |
PaletteSetStyles.ShowCloseButton |
PaletteSetStyles.ShowPropertiesMenu;
_palette.MinimumSize = new System.Drawing.Size(330, 150);
_palette.Name = "XData Palette";
_palette.AddVisual("XDataControl", new View.XDataControl());
}
_palette.Visible = true;
}
}
}