When I try to set Worksheet's Name property using this test application, it doesn't work due to an 0x80028018 error.
When I change the value in the first text box, and I click the tab button, nothing happens, while I expect the Sheet1 to be renamed. In the Visual Studio Output Window I can see the following error:
System.Windows.Data Error: 8 : Cannot save value from target back to source.
BindingExpression:Path=Worksheet.Name; DataItem='ViewModel' (HashCode=35209123); target element is 'TextBox' (Name=''); target property is 'Text' (type 'String')
ExternalException:'System.Runtime.InteropServices.ExternalException (0x80028018): Exception of type 'System.Runtime.InteropServices.ExternalException' was thrown.
at System.Windows.Forms.ComponentModel.Com2Interop.Com2PropertyDescriptor.SetValue(Object component, Object value)
at MS.Internal.Data.PropertyPathWorker.SetValue(Object item, Object value)
at MS.Internal.Data.ClrBindingWorker.UpdateValue(Object value)
at System.Windows.Data.BindingExpression.UpdateSource(Object value)'
The application is a very basic WPF application with a ViewModel class that contains the reference to the Workbook. Then we have a view (xaml) class that binds to the ViewModel.
Viewmodel class:public class ViewModel
{
public Worksheet Worksheet { get; set; }
public ViewModel(Worksheet worksheet)
{
Worksheet = worksheet;
}
public string Name
{
get => Worksheet.Name;
set => Worksheet.Name = value;
}
}
Then, in the view, I have a TextBox control that is bound to the Name property of the Worksheet.
Basically there are two ways of doing this:
<TextBox Text="{Binding Worksheet.Name}"/>
or:
<TextBox Text="{Binding Name}"/>
that's because my ViewModel exposes both Worksheet and Name.
And this is where things get interesting.
If I use the first way, it doesn't work and in the debug output of visual studio I find the error shown above.
If I use the second way it works just fine. This way is through Name property, that in turn means that I have an explicit
Worksheet.Name = ...
in my code (in the Name's setter).
This is the only difference that I see between the two solutions.
Further analysis & questions
The 0x80028018 seems to be a well-known one; there are several articles talking about it.
I read this one:
HowTo: Fix “Old format or invalid type library” error (0x80028018)
but:
- I can't explain why in my application I see two different behaviors
- I can't figure out how to fix the problem at application level so that the binding works as expected
Even if the problem is not so critical and there is an easy workaround for it, there is the risk that it could indicate greater issues. That's why I'm looking for a robust solution.
Left over code, if you want to reproduce itBeyond the ViewModel class there is the very easy xaml view, (only note: implemented as a UserControl because it has to be loaded into an ElementHost). There is an exceeding TextBox just for allowing the first to lose focus and trigger the update.
<UserControl x:Class="ExcelAddIn12.UserControl1"
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:ExcelAddIn12"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<!--the non-working solution: -->
<TextBox Text="{Binding Worksheet.Name}"/>
<TextBox/>
</StackPanel>
</UserControl>
It remains only the launch & wiring code. As a launcher i used a Ribbon (designed, not xaml) with a button.
public partial class Ribbon1
{
private void Ribbon1_Load(object sender, RibbonUIEventArgs e) { }
private void button1_Click(object sender, RibbonControlEventArgs e)
{
Worksheet myWorksheet = (Worksheet)Globals.ThisAddIn.Application.ActiveSheet;
ViewModel vm = new ViewModel(myWorksheet);
UserControl1 view = new UserControl1() { DataContext = vm };
Form form = new Form();
ElementHost wpfHost = new ElementHost() { Dock = DockStyle.Fill, Child = view };
form.Controls.Add(wpfHost);
form.Show();
}
}
Versions:
- Visual Studio 2017 (EN)
- Excel 2010 (EN)