WPF two-way binding with internal setter - wpf

I'm using WPF's two-way binding on a CLR property, which implements INotifyPropertyChanged.
The set for the property is internal, while the get is public.
Unfortunately, I get the following error:
System.Windows.Markup.XamlParseException was unhandled
Message: An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: A TwoWay or OneWayToSource binding cannot work on the read-only property 'Name' of type 'MyType'.
Is this the expected behavior? I would have thought that internal setters should work just fine...
Note that the CLR-type is defined in another assembly, and are visible in the current assembly, with the [assembly: InternalsVisibleTo("MyAssembly")] attribute.
Does anyone have workarounds/suggestions? The declaring assembly is a class library, so it's not an option for me to change the set to public.

You can create your own NEW public wraper property and use getter and setter of it to interact with your internal property
internal string _SideTabHeader;
public string SideTabHeader
{
get { return _SideTabHeader; }
set
{
if( value<0)
{
do nothing
}
else
{
_SideTabHeader=value;
};
}
}

Oh my... I just found out, WPF bindings don't work with internal properties. Oh, Microsoft... Whatever were you thinking?
Update:
Here's what I've understood so far (Thank you, #Grx70):
WPF is not a native part of the .NET framework, it's just a "plug-in" framework that happens to be also written by Microsoft. That is why it can't access the internal members of your assembly.
Microsoft could have allowed WPF to respect the [assembly: InternalsVisibleTo("XXX")] attribute, but as of right now, WPF ignores it - which unfortunately does not leave one with any easy workarounds.
Note: I tested using InternalVisibleTo - both Signed and Unsigned, with PresentationFramework, PresentationCore, and a whole bunch of other DLLs with no luck.
The only workaround I can think of right now is to create a "Proxy" class which can expose all required members as public. This is quite a PITA (I have a LOT of classes, and I hate the maintenance nightmare that comes with creating an equal number of "Proxy" classes) - so I might look into using PostSharp, or Fody or some kind of weaver to auto-create these "Proxy" classes if I can.
All the best to anyone else facing this issue.

This is very late and not solving the initial question, but as very related it may help someone else which very similar problem...
If your internal property is of type Enum else skip
In my case I was trying to do a WPF xaml binding to a property of type inherited from a WCF service. The easy way to solve that simple case was to use int.
public Dictionary<int, string> ProductsList => EnumExtensions.ProductsList;
public int ProductType
{
get { return (int)_DeliveryProduct.ProductType; }
set
{
if (value.Equals(ProductType)) return;
_DeliveryProduct.ProductType = (ProductEnum)value;
RaisePropertyChanged(() => ProductType);
}
}
_DeliveryProduct is my reference to my domain object for which the property ProductType is an enum but in my viewmodel that property is an int.
... Note that ProductEnum is autogenerated from the API and can't be changed to public.
internal static Dictionary<int, string> ProductsList => new Dictionary<int, string>
{
{(int)ProductEnum.Regular, ProductEnum.Regular.GetDisplayName()},
{(int)ProductEnum.Intermediate, ProductEnum.Intermediate.GetDisplayName()},
{(int)ProductEnum.Super, ProductEnum.Super.GetDisplayName()},
{(int)ProductEnum.Diesel, ProductEnum.Diesel.GetDisplayName()}
};

Related

Why Can't I Use My DbContext Type?

I'd like to access some static properties of my DbContext type in a WPF Window. I thought I could use the same XAML that I use to refer to individual entities:
<Window.Resources>
<entity:Account x:Key="account"/> //Works fine
<entity:MyEntities x:Key="myEntities"/> //Throws an error!
</Window.Resources>
I get this error:
No connection string named 'MyEntities' could be found in the application config file.
Why is it treating the DbContext type (MyEntities) differently than the Account entity? Is there an easy way I can access the static properties of my MyEntities type?
The syntax you used is for creating instances, not static properties. If you want to access a static property you need to use the x:Static markup extension
<Window.Resources>
<entity:Account x:Key="account" SomeProperty={x:Static entity:MyEntities.MyProperty}/>
</Window.Resources>
The above xaml would be similar to the C# code
var account = new Account()
{
SomeProperty = MyEntities.MyProperty
};
this.Resources["account"] = account;
See that you are calling new Account(), if you called new MyEntites() (like your original example did) you get the error you where getting.
It appears that particular error results due to the static constructor that I placed in my DbContext. When I remove the static constructor the error changes to:
Object reference not set to an instance of an object.
As it turns out, the original error doesn't prevent me from compiling or running my application. I changed my code to use Scott Chamberlain's suggestion (which produces a similar ignorable error) because it is much cleaner and I can access the static properties on the DbContext just fine in spite of Visual Studio's complaints. Thanks, everyone, for the help and suggestions.

What replaces the obsolete property Window.PersistId

I am using the code at:
http://www.codeproject.com/Articles/15926/Save-and-Restore-the-Location-Position-and-State-o
to persist my XAML window location.
#region WindowApplicationSettings Helper Class
public class WindowApplicationSettings : ApplicationSettingsBase
{
private WindowSettings windowSettings;
public WindowApplicationSettings(WindowSettings windowSettings)
: base(windowSettings.window.PersistId.ToString())
{
this.windowSettings = windowSettings;
}
Unfortunately the code makes use of Window.PersistId which Microsoft have now made obsolete.
"PersistId is an obsolete property and may be removed in a future
release. The value of this property is not defined."
What would be the best way to replace this property?
I don't know which property should be used instead of PersistId.
I found this solution though for persisting the window settings. I didn't try it myself though.
http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/

from VBS to WPF via COM

we have a nasty (or maybe a trivial?) issue.
There is a WPF control. It has 2 interfaces, the main and one for automated testing purpose. Defined this way:
[ComVisible(true)]
[Guid("xxx")]
public interface IXXXXXTest
{
[DispId(1)]
void Test1(int index);
}
[ComVisible(true)]
public interface IXXXXX
{
void Main1(index);
}
[ComVisible(true)]
[Guid("xxx")]
ClassInterface(ClassInterfaceType.None)]
public partial class XXXXX_WPF_CONTROL : UserControl,
IXXXXX,
IXXXXXTest
{
...
}
Now we are trying to reach it from VBS.
Try 1)
Set Ctrl = GetControl(...) <---- this is ok
Ctrl.Test1(0) <---- Object doesn't support this property or method: 'Ctrl.Test1'
Set Ctrl = GetControl(...) <---- this is ok
Ctrl.Main1(0) <---- this is ok
So it works fine for the "main" interface but for the test interface.
This seems ok(?), because as far as I know VBS reaches the "main" interface only via IDispatch if there is no IDispatchEx. So I added a property to the IXXXXX to get the test interface.
[ComVisible(true)]
public interface IXXXXX
{
void Main1(index);
IXXXXXTest Test { get;}
}
....
public IXXXXXTest Test
{
get { return this as IXXXXXTest; }
}
Great, so now I can reach this IXXXXTest interface via the "main" interface.
Try 2)
VBS:
Set Ctrl = GetControl(...) <---- this is ok
Set CtrlTest = Ctrl.Test <----- this is ok
CtrlTest.Test1(0) <---- Object doesn't support this property or method: 'CtrlTest.Test1'
:(
Note that, for an other .NET control of us the "Try1" works, without any trick!
So probably due to the WPF something different?
Also, changing the
ClassInterface(ClassInterfaceType.None)]
into anything else (AutoDispatch / AutoDual), or leaving it makes the WPF control unusable.
Besides that this is also how it should be by this article: Is it possible to package WPF window as COM Object
Do you have any idea what could be the problem?
Thank much in advance!
Scripting languages can only use the default interface on a class. You've got more than one so at least one of them will not be usable. And method names may be renamed if they conflict with other declarations. I'd assume you obfuscated the real names in your question so hard to diagnose such a renaming happening from what you posted.
Best thing to do is to temporarily apply the [InterfaceType(ComInterfaceType.InterfaceIsDual)] attribute on your interface types. Which allows you to generate a type library with Tlbexp.exe which you can then view with the OleView.exe utility, File + View Typelib command. You'll see the exact names of the methods and you'll see which interface is the [default] one on the coclass. From there you should have little trouble modifying your declarations so they'll work in a scripting language.

How to tag viewmodels when registering for MVVM messages?

Using MVVM Light, it is easy to register for certain types of messages:
public MyViewModel()
{
Messaging.Messenger.Default.Register<MyObject>(this,
new Action<MyObject>((o) => DataMember = o));
}
Now, I have multiple document views in my software which implies showing/hiding views when toggling between them. When a view instance is hidden, I want its registered messages to be ignored. Similarly, when a view instance is shown, I want its registered messages to be handled. Hence, a message token per document is required:
public MyViewModel(String documentID)
{
Messaging.Messenger.Default.Register<MyObject>(this,
documentID,
new Action<MyObject>((o) => DataMember = o));
}
The problem is, I cannot figure out where in XAML/code to specify this token!
Sure, I can provide the documentID from the view...
public MyView()
{
InitializeComponent();
DataContext = new MyViewModel("1234");
}
... effectively giving me the same problem. Where would I specify this "1234" value? I read about x:Arguments Directive, hoping that it would let me specify constructor arguments in XAML, but it seems it's only supported in Loose XAML :(
I can think of a couple of solutions, like having a global variable, ActiveDocumentID, that would be used as token when instantiating the viewmodel. Is there a better solution?

What use has RoutedCommand' class constructor ownertype argument?

The constructor of the RoutedCommand has "owner type" as a last argument. What is its significance? When it is used?
MSDN documentation gives completely no clue about why it's needed and whether I could use one type for all commands
Quote from MSDN
ownerType
Type: System.Type The type
which is registering the command.
There is one more thing. What type should I use when creating new routed commands dynamically from array of names. It looks like that any type works, so I'm using UIElement, but if there is a more suited type for this I would like to know.
The source for RoutedCommand shows that the type becomes the OwnerType property. This property is queried ultimately by the following private method when getting InputGestures. So it looks as though this type is being used to lookup a (hard-coded) set of Commands based on the type that created the RoutedCommand.
private InputGestureCollection GetInputGestures()
{
if (this.OwnerType == typeof(ApplicationCommands))
{
return ApplicationCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(NavigationCommands))
{
return NavigationCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(MediaCommands))
{
return MediaCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(ComponentCommands))
{
return ComponentCommands.LoadDefaultGestureFromResource(this._commandId);
}
return new InputGestureCollection();
}
I know this is a very old question, but it's the top search hit for "routedcommand ownertype".
Storing an OwnerType and Name within each RoutedCommand object gives you a hint on how to find references to it in code. Suppose you are running the debugger on some method that has an arbitrary ICommandSource parameter. You can examine the Command property, and if you see that OwnerType is CommonCommands and Name is "DoSomething", you can navigate to the DoSomething field of the CommonCommands class, where there might be a useful comment, or search for references to CommonCommands.DoSomething to find associated CommandBindings or something. Without those properties, the RoutedCommand would just be an anonymous object.
I don't know if that reason was what the API designers actually had in mind when they included the argument, but it has been useful to me at least.

Resources