Error when trying to use markup extension - c#

I have a small window that I am trying to load when my application starts. Here is the (loose) XAML:
<ctrl:MainWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Controls;assembly=Controls">
<Grid>
<ctrl:ConnectionStatusIndicator/>
<TextBlock Grid.Row="2" Text="{Resx ResxName=MyApp.MainDialog, Key=MyLabel}"/>
</Grid>
</ctrl:MainWindow>
Notice the custom control called ConnectionStatusIndicator. The code for it is:
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public class ConnectionStatusIndicator : Control
{
public ConnectionStatusIndicator()
{
}
static ConnectionStatusIndicator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ConnectionStatusIndicator),
new FrameworkPropertyMetadata(typeof(ConnectionStatusIndicator)));
IsConnectedProperty = DependencyProperty.Register("IsConnected", typeof(bool), typeof(ConnectionStatusIndicator), new FrameworkPropertyMetadata(false));
}
public bool IsConnected
{
set { SetValue(IsConnectedProperty, value); }
get { return (bool)GetValue(IsConnectedProperty); }
}
private static DependencyProperty IsConnectedProperty;
}
}
Now, here is where it gets weird (to me, at least). With the XAML as it appears above, my application will build and run just fine. However, if I remove the following line:
<ctrl:ConnectionStatusIndicator/>
or event move it one line down, I get the following error:
Additional information: 'Cannot create unknown type
'{http://schemas.microsoft.com/winfx/2006/xaml/presentation}Resx'.'
Line number '13' and line position '33'.
What is really strange to me is that, if I replace ConnectionStatusIndicator with another custom control from the same assembly, I get the error. The other custom control is very similar, but has a few more properties.
Can anyone explain what is going on here?

The Resx markup extension belongs to the Infralution.Localization.Wpf namespace but also does something a bit hackish and attempts to register itself to the http://schemas.microsoft.com/winfx/2006/xaml/presentation xml namespace to allow developers to use it as {Resx ...} instead of having to declare the namespace in XAML and use the extension with a prefix {resxNs:Resx ...}.
I believe that if you clean up your solution and possible delete your *.sou file the project will build as expected, but a sure way to solve this will be to add an xmlns declaration for Infralution.Localization.Wpf and use the extension with the xmlns prefix:
<ctrl:MainWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Controls;assembly=Controls"
xmlns:loc="clr-namespace:Infralution.Localization.Wpf;assembly=Infralution.Localization.Wpf">
<Grid>
<ctrl:ConnectionStatusIndicator/>
<TextBlock Grid.Row="2" Text="{loc:Resx ResxName=MyApp.MainDialog, Key=MyLabel}"/>
</Grid>
</ctrl:MainWindow>
Also, for anyone interested, the "hack" is in these lines in the localization library:
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Infralution.Localization.Wpf")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2007/xaml/presentation", "Infralution.Localization.Wpf")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2008/xaml/presentation", "Infralution.Localization.Wpf")]

Related

WPF/XAML: How to reference class that is not defined within any namespace

I'm executing a roslyn script that tries to define and open a WPF window.
Amongst other things, my script
defines an attached behavior
defines a XAML string, based on which I create a WPF Window. In this XAML code, I'd like to use the TextBoxCursorPositionBehavior defined in my script.
my script (.csx) file looks similar to
public class TextBoxCursorPositionBehavior : DependencyObject
{
// see http://stackoverflow.com/questions/28233878/how-to-bind-to-caretindex-aka-curser-position-of-an-textbox
}
public class MyGui
{
public void Show()
{
string xaml = File.ReadAllText(#"GUI_Definition.xaml");
using (var sr = ToStream(xaml))
{
System.Windows.Markup.ParserContext parserContext = new System.Windows.Markup.ParserContext();
parserContext.XmlnsDictionary.Add( "", "http://schemas.microsoft.com/winfx/2006/xaml/presentation" );
parserContext.XmlnsDictionary.Add( "x", "http://schemas.microsoft.com/winfx/2006/xaml" );
parserContext.XmlnsDictionary.Add("i","clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity");
// ?? How can i define this properly?
parserContext.XmlnsDictionary.Add("behaviors", "clr-namespace:;assembly=" + typeof(TextBoxCursorPositionBehavior).Assembly.FullName);
var window = (System.Windows.Window)XamlReader.Load(sr, parserContext);
window.ShowDialog();
}
}
}
and assume the GUI_Definition.xaml looks like
<Window x:Class="System.Windows.Window" Height="300" Width="300" >
<Grid>
<!-- how can i attach my behavior here properly? -->
<TextBox behaviors:TextBoxCursorPositionBehavior.TrackCaretIndex="True"/>
</Grid>
</Window>
But the problem is, how can I reference TextBoxCursorPositionBehavior correctly in XAML?
Roslyn doesn't allow to use namespaces in script files, so TextBoxCursorPositionBehavior must be defined outstide of a namespace (i.e. I suppose it will fall into the global namespace).
But then, how can I reference it in XAML? I've tried defining the namespace reference with "clr-namespace:;assembly=" + typeof(TextBoxCursorPositionBehavior).ToString(), but that doesn't work.
Simply "clr-namespace:" (i.e. without assembly reference) doesn't work either.
Is there any way to reference TextBoxCursorPositionBehavior from within the XAML definition?
In your code instead of assembly you use:
typeof(TextBoxCursorPositionBehavior).ToString()
This is not an assembly name. Change it to:
parserContext.XmlnsDictionary.Add("behaviors", "clr-namespace:;assembly=" + Assembly.GetExecutingAssembly().FullName);
And it should work fine (at least works for me, but I don't test with Roslyn script but just regular WPF application).
I think I know what's happening ... Roslyn creates a custom Submission type for scripts, and seems everything - including the definition of TextBoxCursorPointerBehavior - is a sub-class of this submission type. I.e.,
var inst = new TextBoxCursorPositionBehavior();
string typeName = inst.GetType().FullName;
typeName will not be "TextBoxCursorPointerBehavior", but rather "Submission#0+TextBoxCursorPositionBehavior".
At the same time, I can NOT reference this from XAML (e.g. by behaviors:Submission#0+TextBoxCursorPositionBehavior.TrackCaretIndex="True") as it won't parse the name correctly (# is an invalid token there).
In theory, it might be possible to rename Roslyn's submission type to something that is actually referencable via XAML - in my case though, I cannot do that.
Which unfortunately currently means I don't see any solution to my issue, other than possibly outsourcing this code to a separate pre-compiled DLL (but that's not quite the point of scripting either)

XAML Designer Crashes with Self-Registering ViewModel

The XAML designer crashes visual studio 2010 if the view model that is set as the Data Context registers itself in a static class.
View
<Window x:Class="CTL.Editor.View.EditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editor="clr-namespace:CTL.Editor.ViewModel.Editor"
Height="300" Width="300">
<Window.DataContext>
<editor:EditorWindowViewModel />
</Window.DataContext>
<Grid>
</Grid>
</Window>
ViewModel:
public EditorWindowViewModel()
{
ApplicationViewModel.EditorWindows.Add(this);
}
~EditorWindowViewModel()
{
ApplicationViewModel.EditorWindows.Remove(this);
}
Is there any way around this? Maybe a # directive?
You can use the DesignerProperties.IsInDesignMode to supress execution while in design mode. Just wrap your code in an if statement: if(!DesignerProperties.IsInDesignTool)
However it is often a good idea to find the root cause of the problem by debugging the designer exception. Here is an good article that should get you started.
For those seeking a bit more detail than Postlagerkarte's answer:
A way to use IsInDesignMode that is MVVM-friendly is shown below.
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
....
}
My issue was caused by the fact that ApplicationViewModel's constructor what loading a config file and apparently Visual Studio didn't like that, didn't find the file or didn't search for the file in the right place when it was running my code.
What I ended up doing was:
public static bool DesignMode
{
get { return DesignerProperties.GetIsInDesignMode(new DependencyObject()); }
}
static ApplicationViewModel()
{
if (!DesignMode)
{
Configuration = Configuration.LoadConfigurationDocument();
}
}
Note: There is a Configuration static member on ApplicationViewModel and a Configuration class which loads the config.

Is this namespace collision due to a bug in the XAML to .NET code generation?

Below I describe how to reproduce an error I'm receiving. It behaves the same in VS 2010, 2012, and 2013. Breaking it into multiple projects, as I indicate below, is important.
Steps to reproduce the error:
Create a solution.
Create a C# class library called Common, containing one file named Handler.cs:
using System;
namespace Common
{
public delegate void Handler(object sender, EventArgs args);
}
Create a WPF user control library project called MyControlLibrary, referencing Common. In it, create a user control called MyControl.xaml.
MyControl.xaml:
<UserControl x:Class="ControlNamespace.MyControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
</Grid>
</UserControl>
MyControl.xaml.cs:
using System.Windows.Controls;
using Common;
namespace ControlNamespace
{
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
public event Handler MyEvent;
}
}
Create a WPF Application project called MyWpfApplication, referencing Common and MyControlLibrary. In it, create WindowNamespace.Common.cs as well as a window called MyWindow.xaml.
WindowNamespace.Common.cs:
namespace WindowNamespace.Common
{
}
MyWindow.xaml:
<Window x:Class="WindowNamespace.MyWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:ControlNamespace;assembly=WpfControlLibrary1"
Title="MyWindow" Height="300" Width="300">
<Grid>
<c:MyControl MyEvent="MyControl_MyEvent" />
</Grid>
</Window>
MyWindow.xaml.cs:
using System;
using System.Windows;
namespace WindowNamespace
{
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
}
void MyControl_MyEvent(object sender, EventArgs args)
{
}
}
}
Build the solution.
You should receive the following error, pointing to line 7 of MyWindow.xaml:
The type or namespace name 'Handler' does not exist in the namespace
'WindowNamespace.Common' (are you missing an assembly reference?)
If you open the .g.i.cs file generated for MyWindow.xaml, you should see the following in the IComponentConnector.Connect method:
#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new Common.Handler(this.MyControl_MyEvent);
The source of the issue is that it is trying to find Common.Handler in WindowNamespace. This could be resolved by having it generated as:
#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new global::Common.Handler(this.MyControl_MyEvent);
Or by adding a using to the top of the file:
using Common;
...
#line 7 "..\..\MyWindow.xaml"
((ControlNamespace.MyControl)(target)).MyEvent += new Handler(this.MyControl_MyEvent);
Note that if all these source files are bundled into a single project, the error goes away, because the .g.i.cs file is generated differently (i.e. it doesn't explicitly add the handler to the event).
Is this actually a bug in the XAML->.NET translation, or is there something I am doing wrong?
There's a clue as to what's happening if you redeclare the Handler delegate in your WindowNamespace.Common namespace declaration in MyWpfApplication and try to compile:
Error 1 Cannot implicitly convert type 'WindowNamespace.Common.Handler' to 'Common.Handler' c:\Dev\YourSolution\MyWpfApplication\MyWindow.xaml 7 63 MyWpfApplication
The Common project is declaring a global namespace called "Common", which your control library is also using. But when your application explicitly declares "WindowNamespace.Common" it creates a local namespace which just so happens to be the same namespace that the parent control resides in. This effectively creates the ambiguity problem described in the Visual Studio documentation for Compiler Error CS0433.
Change your common namespace declaration in MyWpfApplication to just be "Common" and the problem will go away.

Data binding window title to application resource

Currently I'm doing it so:
public MainWindow()
{
InitializeComponent();
Title = Properties.Resources.WindowName;
}
How to do the same through the WPF binding?
EDIT: It still doesn't work in XAML.
Environment:VS2010, .NET 4.0, Windows 7.
Reproduction steps:
Create class library ClassLibrary1 with code:
namespace ClassLibrary1
{
static public class Class1
{
static public string Something
{
get { return "something"; }
}
}
}
Create WPF windows application in VS2010 .NET 4.0.
Edit main window's XAML:
<Window x:Class="ahtranslator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ClassLibrary1="clr-namespace:ClassLibrary1;assembly=ClassLibrary1"
Title="{Binding Source={x:Static ClassLibrary1:Class1}, Path=Something}"
Height="350" Width="525" Icon="/ahtranslator;component/Icon1.ico" WindowStyle="SingleBorderWindow" ShowInTaskbar="False" DataContext="{Binding}">
...
Compilation error message:
MainWindow.xaml(7,130): error MC3029: 'ClassLibrary1:Class1' member is not valid because it does not have a qualifying type name.
Also I found this topic My.Resources in WPF XAML?.
And it seems all should work but it doesn't.
Microsoft doesn't give description for this error message. Only another topic in help forum http://social.msdn.microsoft.com/Forums/en/wpf/thread/4fe7d58d-785f-434c-bef3-31bd9e400691, which doesn't help either.
In code it would look like this i think:
Binding titleBinding = new Binding("WindowName");
titleBinding.Source = Properties.Resources;
this.SetBinding(Window.Title, titleBinding);
This only makes sense if changes may occur to the title and the binding will be notified of those changes (WindowName has to either be a Dependency Property or Resources needs to implement INotifyPropertyChanged)
If Properties is a namespace (as would be the case with the default VS-generated properties) you need to declare it somewhere using xmlns & use x:Static:
<Window
...
xmlns:prop="clr-namespace:App.Properties"
Title="{Binding Source={x:Static prop:Resources.WindowName}}">
Another note: If you use the managed resources of Visual Studio you need to make sure that the access modifier of the properties is public, default is internal which will throw an exception since binding only works for public properties.
just remove this:
... ;assembly=ClassLibrary1"
I actually have the Title in a static resource defined at the top of the application and I bind the Title and anything else I want to it
<s:String x:Key="ApplicationName">My Application</s:String>
Have you tried to change the access modifier of the resource from internal to public?
I have just had some problem with that right now.
/// <summary>
/// Looks up a localized string similar to Has been impossible to load the configuration information.
/// </summary>
internal static string ERROR_NoConfigurationLoaded {
get {
return ResourceManager.GetString("ERROR_NoConfigurationLoaded", resourceCulture);
}
}
to
/// <summary>
/// Looks up a localized string similar to Has been impossible to load the configuration information.
/// </summary>
public static string ERROR_NoConfigurationLoaded {
get {
return ResourceManager.GetString("ERROR_NoConfigurationLoaded", resourceCulture);
}
}

WPF: XAML namespace

I have one assembly XAML registered in AssemblyInfo.cs:
[assembly: XmlnsDefinition("http://schemas.mysite.es/wpf", "SWC.ViewModels")]
And In my namespace I hace these classes:
namespace SWC.ViewModels
{
public class MenuViewModel
: ObservableCollection<MenuViewModel>
{
public MenuViewModel()
: base()
{
}
}
}
If I use the namespace in a user control XAML,
<UserControl x:Class="SWC.UserControls.UserMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:customMenu="http://schemas.mysite.es/wpf">
I can use the class in my XMLNS namespace,
<UserControl.Resources>
<customMenu:MenuViewModel x:Key="MenuItemsSource">
But, when I execute the application, the compiler said
The label 'MenuViewModel' dosen't exist in the namespace XML 'http://schemas.mysite.es/wpf'
All, can help me?? I'm crazy with this problem!!
Best regards,
I think you need to specify the assembly in which your customMenu controls exist. The assembly must also be referenced from the project (in the References section).
xmlns:customMenu="clr-namespace:customMenuNamespace;assembly=customMenuLibrary"
Otherwise I don't see how the compiler can find your implementation only through "http://schemas.mysite.es/wpf". What's at that address? The two microsoft schemas
http://schemas.microsoft.com/winfx/2006/xaml/presentation
http://http://schemas.microsoft.com/winfx/2006/xaml
work like some identifiers for the xaml compiler, there is nothing at those addresses.

Categories

Resources