Design Time - Dynamic - wpf

can i create a view at design time, using dynamic objects? (with visual studio 2010)
for example, or something, is that possible?
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dyn="clr-namespace:System.Dynamic;assembly=System.Core"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
and
<d:DesignProperties.DataContext>
<dyn:ExpandoObject>
<dyn:ExpandoObject.Name>MyName</dyn:ExpandoObject.Name>
</dyn:ExpandoObject>
</d:DesignProperties.DataContext>
The above example does not work.
Sometimes I have class complicated to manage. And I can not use them at design time, the idea of using a dynamic type would be not to change the bindings (properties that I will use) and get a vision.
I do not know if I was clear, but if you have something that can help me would be great.

That should not work in any case, be it design or run-time.
You can use ExpandoObjects, but only via dictionary syntax:
<dyn:ExpandoObject>
<sys:String x:Key="Name">MyName</sys:String>
</dyn:ExpandoObject>
Though i do not know if that junk of a GUI designer is able to handle that, nor do i know if this works with compiled XAML.
Edit: As i thought you cannot compile this because some component fails:
Error 1 The Key attribute can only be used on a tag contained in a Dictionary (such as a ResourceDictionary).
Well, it is a bloody dictionary alright...
You can use a markup extension though, you can get the DictionaryFactoryExtension from this answer and modify it like this:
public override object ProvideValue(IServiceProvider serviceProvider)
{
var expando = (IDictionary<string,object>)new ExpandoObject();
foreach (DictionaryEntry kvp in Dictionary)
expando[(string)kvp.Key] = kvp.Value;
return expando;
}
//The designer uses this for whatever reason...
public object this[object key]
{
get { return this.Dictionary[key]; }
set { this.Dictionary[key] = value; }
}
Then you can use that just like an ExpandoObject:
<!-- Of course you can also hard-code the key-type in the class,
it should be a string in all cases when using an ExpandoObject anyway -->
<local:DictionaryFactory KeyType="sys:String" ValueType="sys:Object">
<sys:String x:Key="Name">MyName</sys:String>
</local:DictionaryFactory>
The designer should be able to handle this.

Related

Get Assembly where instance is declared in XAML

I have a framework.dll, customerFramework.dll and customer.exe.
Inside of the framework.dll is a customControl declared which can be placed in customerFramework.dll (in a XAML page/window) or in customer.exe (in a XAML page/window).
The customControl got a public DependencyProperty of type Uri. Visual Studio supports IntelliSense for its resources, so it is very easy to set these properties.
During runtime, the CustomControl tries to resolve the resources inside of framework.dll, but they are declared in:
customer.exe
To fix this issue, I have to set the following prefix: /customer;component/ballon.svg.
customerFramework.dll
To fix this issue, I have to set the following prefix: /customerFramework;component/ballon.svg.
But if I do so, I don't have any IntelliSense. So I would like to combine the right uri by adding the prefix in code behind.
What I want to know is the assembly name inside of the customControl, where the customControl has been placed.
If the customControl is placed in customerFramework.dll and I use the Assembly.() methods, I get the wrong informations (expected value: customerFramework):
GetEntryAssembly(): customer.exe
GetCallingAssembly(): framework.dll
GetExecutingAssembly(): framework.dll
Is there a hidden function to get this information?
sorry man i misunderstood the question .
please use reflection with stacktrace
var currentAssembly = Assembly.GetExecutingAssembly();
var callerAssemblies = new StackTrace().GetFrames()
.Select(x => x.GetMethod().ReflectedType.Assembly).Distinct()
.Where(x => x.GetReferencedAssemblies().Any(y => y.FullName == currentAssembly.FullName));
var initialAssembly = callerAssemblies.Last();
Code will be slow because it use reflection . good luck.

WPF two-way binding with internal setter

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()}
};

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.

How to display application title in XAML text field

I have a Windows Phone page code that is shared by multiple applications.
At the top of the page, I show the title of the application, like so:
Is it possible to make the text be bound to the application title as defined in the application's assembly?
I realise that I could do this by code by reading the title in the assembly and then doing something like:
this.ApplicationTitle.Text = title;
I was hoping that the title as defined in the assembly could be accessed with some magic like:
Text={assembly title}" directly from within the xaml.
Thanks
Create a property called ApplicationTitle that returns that name of the application like the following, and then bind to it in XAML:
public string ApplicationTitle
{
get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; }
}
(You can use a relative binding source if you can't or don't want to use the data context.)
edit:
I just realized that my method involved security considerations since GetName is a method that is [Security Critical]. And I got a MethodAccessException stating: Attempt to access the method failed: System.Reflection.Assembly.GetName()
So here's another way to get the assembly name and return it in a property by using the AssemblyTitle attribute.
public string ApplicationTitle
{
get
{
System.Reflection.AssemblyTitleAttribute ata =
System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(
typeof(System.Reflection.AssemblyTitleAttribute), false)[0] as System.Reflection.AssemblyTitleAttribute;
return ata.Title;
}
}
To bind in XAML, you can use this:
Text="{Binding ElementName=LayoutRoot, Path=Parent.ApplicationTitle}"

Silverlight InlineCollection.Add(InlineUIContainer) missing?

I'm having difficulty adding the inline of specific type InlineUIContainer into the InlineCollection (Content property) of a TextBlock. It appears the .Add() method of InlineCollection doesn't accept this type, however you can clearly set it through XAML without explicitly marking the content as a InlineContainer, as demonstrated in many examples:
http://msdn.microsoft.com/en-us/library/system.windows.documents.inlineuicontainer.aspx
Is it possible to programatically add one of these as in the following?
Target.Inlines.Add(new Run() { Text = "Test" });
Target.Inlines.Add(new InlineUIContainer() {
Child = new Image() { Source = new BitmapImage(new Uri("http://example.com/someimage.jpg")) } });
Target.Inlines.Add(new Run() { Text = "TestEnd" });
I have a feeling what's going on is that Silverlight is using a value converter to create the runs when specified in XAML as in the example which doesn't use InlineContainer, but I'm not sure where to look to find out.
The specific error I'm getting is as follows:
Cannot add value of type 'System.Windows.Documents.InlineUIContainer' to a 'InlineCollection' in a 'System.Windows.Controls.TextBlock'.
As pointed out by Jedidja, we need to use RichTextBox to do this in Silverlight.
You can't Add() Runs directly, but you can add Spans containing Runs.
Interestingly, you can also do this:
textBlock.Inlines.Clear();
textBlock.Inlines.Add(new Span());
textBlock.Inlines[0] = new Run();
Not that it's a good idea to hack around what the framework is actively trying to prevent you from doing.
P.S. If you can't figure out what XAML is doing, inspect the visual tree.

Resources