I want my user control to display data when I am viewing it in the WPF designer in Visual Studio.
The ViewModel does not have a default constructor, so I wrote my own static TestData class to construct the model and all of its dependencies.
public static class TestData
{
public static ELabelViewModel ELabelViewModel
{
get
{
return new ELabelViewModel
(
new ControlPanelGridLine(TestData.ELabel),
new SerialPortFactoryImpl(),
new Repository(),
new PriceLabelGenerator(TestData.IPriceLabelViewModelFactory)
);
}
}
// Other static getter methods
This all compiles with no problems. However, problems start when I add this in the XAML:
d:DataContext="{x:Static local:TestData.ELabelViewModel}"
The XAML editor puts a curly blue line under my d:DataContext attribute, and in the error list I see:
Error 7 Method not found: 'Void
ELabel.Manager.ViewModels.ELabelViewModel..ctor(ELabel.Manager.ViewModels.ControlPanelGridLine,
ELabel.Control.ISerialPortFactory, ELabel.Data.IRepository,
ELabel.ImageGeneration.IPriceLabelGenerator)'.
My interpretation of this is that it is finding the TestData class, and also finding the TestData.ELabelViewModel property. It just cannot resolve the constructor that is being called inside the getter.
Why can it not find the ELabelViewModel constructor? To confirm my code was OK, I made this test view model the actual data context by using DataContext= instead of d:DataContext=. In this case I opened the application and confirmed that, at runtime, all works as expected: TestData.ELabelViewModel was invoked, the code insider the getter function ran, and it used this view model. It's just the designer that is failing to run the code.
The ELabelViewModel class is in a separate assembly called ELabel.Manager.ViewModels. Is the editor failing to fully load this assembly?
Later Edit
I tried moving this TestData class to the ELabel.Manager.ViewModels assembly (the same assembly that the constructor resides in). Sure enough, it now works fine, and I can see test data when viewing the control in the editor. Curious.
I've double-checked that the ELabelViewModel class and the constructor are public (Which of course it is, otherwise I never would have been able to build the application).
I implement all my viewmodel classes like this:
<UserControl x:Class="MyApp.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vm="clr-namespace:MyApp.ViewModel"
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" Height="607" Width="616">
<UserControl.DataContext>
<vm:TestData/>
</UserControl.DataContext>
Related
I have a very simple wpf custom control that defines two constructors:
public class SomeControl : System.Windows.Controls.Button
{
public SomeControl()
{
}
public SomeControl(ISomeService service)
{
}
}
This control is defined in a class library called ControlLib. The ISomeService interface is defined in another class library project called ServiceContracts and ControlLib has a reference to it.
The third project in the solution (called FrontEnd) is a simple WPF-project and i place the custom control on the MainWindow like this:
<Window x:Class="FrontEnd.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:ControlLib;assembly=ControlLib"
Height="450"
Width="800">
<Grid>
<controls:SomeControl />
</Grid>
Until now, everything works fine and as intended. The project structure looks roughly like this:
The problem occurs when i give the costum control a name. When i set the Name attribute like this <controls:SomeControl x:Name="OhWhy" /> the project does not longer compile. I get the following error:
Unknown build error, 'Cannot resolve dependency to assembly 'ServiceContracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it has not been preloaded. When using the ReflectionOnly APIs, dependent assemblies must be pre-loaded or loaded on demand through the ReflectionOnlyAssemblyResolve event. Line 8 Position 31.' FrontEnd C:\01_Data\Tmp\SomeSolution\FrontEnd\MainWindow.xaml 8
My question is: Why does it break when i add the Name-attribute and why does it work in the first place?
I know that setting the Name-attribute will add a field to the designer generated *.g.i.cs file to access the control from code behind, but compilation also breaks when i do the same in a template in some resource dictionary without any designer generated files.
The following things solved the problem but im not exactly sure why:
Adding a reference in FrontEnd to ServiceContracts
Making the parametrized constructor internal
This is caused by the XAML compiler. Please refer to the following question for more information.
Cannot resolve dependency to assembly 'PostSharp' because it has not been preloaded
The solution is to add a reference to ServiceContracts.dll from the WPF application project.
I think what is happening with giving it a name is that you get a local member variable of type SomeControl in FrontEnd. This pulls in the dependency. Before that, you just have baml in a resource and when the baml is deserialized at runtime, the SomeControl type is already loaded in the AddDomain and can be dynamically instantiated using reflection.
I've got a Resource Dictionary called EditorResources.xaml and it contains the following code:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editors="clr-namespace:MyCompany.Editors">
<DataTemplate x:Key="PasswordEditorDataTemplate">
</DataTemplate>
</ResourceDictionary>
But when I include this line of code in a class:
private EditorResources res = new EditorResources();
It doesn't compile my project. I doesn't display any Errors List view in the .NET IDE but when I look at my Output view, it displays the following error:
error CS0246: The type or namespace name 'EditorResources' could not be found (are you missing a using directive or an assembly reference?)
But, I don't believe the reference is missing as both the resource dictionary and class are in the same project (same level) and I can clearly see the EditorResources type highlighted as Type and IntelliSense kicks in as expected when I hit my '.' key and it displays properties relevant to a Resource Dictionary i.e. .MergeDictionaries, etc...
UPDATE:
if like me, you've stored your resource dictionary (editorresources.xaml) in a sub-folder (Editors), and your assembly is called 'MyCompany.Activity.Shared' for example, don't forget to include the sub-folder in the component's part so that when you call the code provided by #DrewNoakes, you can call the following without any problems:
var res = new ResourceDictionary
{
Source = new Uri("/MyCompany.Activity.Shared;component/editors/editorresources.xaml",
UriKind.RelativeOrAbsolute)
};
Once you have your object, you can access your DataTemplates or other via code.
Seems like you have a EditorResources.xaml file but not a corresponding EditorResources.xaml.cs file.
In this case, the type your XAML file defines is ResourceDictionary. If you wish to have a subclass of that, you need to define the partial backing class and add the relevant attributes in the XAML to link them together.
If you don't need any C# code behind the scenes, just load the ResourceDictionary directly.
Some code like this might help:
var dict = new ResourceDictionary
{
Source = new Uri("/YourAssemblyName;component/EditorResources.xaml",
UriKind.RelativeOrAbsolute)
}
I've got a custom user control with a public property that I'd like to be able to set in XAML. Here it is below.
TestControl.xaml
<UserControl x:Class="Scale.Controls.TestControl"
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">
TestControl.xaml.cs
using System.Windows.Controls;
namespace MyProject.Controls
{
public partial class TestControl : UserControl
{
public string TestMe { get; set; }
public TestControl()
{
InitializeComponent();
}
}
}
Then, in my MainWindow.xaml file, I try to include this:
<controls:TestControl TestMe="asdf" />
However, even though Visual Studio autocompletes the TestMe property, I then see things with a squiggly underline that says "The member "Test Me" is not recognized or is not accessible," as seen below.
I could have sworn I've done something like this before in other projects. How can I access (i.e. set) the public properties via XAML like this?
Visual Studio 2017
I had exactly the same problem. It was compiling one day ... and then it wasn't. I wasn't using DependencyProperty which shouldn't be needed as above. The properties were appearing in Intellisense but gave the same message when inserted. I cleaned, built, rebuilt, restarted VS, rebooted etc. All to no avail.
Last ditch try ... I removed all the offending attributes and got a clean compile. Then I put them back and it compiled. I really wasn't expecting that. Somehow VS had gotten its knickers in a twist.
If you are using VS2017, try to delete bin and obj folders in all projects of your solution, clean the solution and build again. It works for me !
You need to declare your property as Dependency Properties
namespace MyProject.Controls
{
public partial class TestControl : UserControl
{
//Register Dependency Property
public static readonly DependencyProperty TestMeDependency = DependencyProperty.Register("MyProperty", typeof(string), typeof(TestControl));
public string MyCar
{
get
{
return (string)GetValue(TestMeDependency);
}
set
{
SetValue(TestMeDependency, value);
}
}
public TestControl()
{
InitializeComponent();
}
}
}
Change the build target from AnyCPU to either x86 or x64. Unsure why AnyCPU does not work.
I know this is late but I just ran into this issue on VS 2020.
I tried all 3 options listed above and none of them worked including the CPU build.
I ended up having to right-click each project, clean, and rebuild. Then it solved the issue...
Really annoying this is still an issue.
In my case, there're no errors originally, after I modify my class, there're some errors in my class then the Xaml Error member is not recognized show. After solving errors in my class, I pass building the projects, all projects are built without errors, but the errors still show in the Error List Window. In the end, I restart Visual Studio, the errors disappear.
I faced this problem with my VS2022, I just removed WindowsBase reference, and it worked.
instead of setting multiple dependency properties for the control, I would use reflection.
public static readonly DependencyProperty UserControlProperty = DependencyProperty.Register("UserControl",
typeof(object), typeof(CustomUserControl), new PropertyMetadata(null));
public object UserControl
{
get { return GetValue(UserControlProperty); }
set { SetValue(UserControlProperty, value); }
}
I have really strange problem. I've created WPF project in 2012 or 2013 VS it doesn't matter. I use .NET 4.5.
I add a new Activity (Workflow class) to that project. Its name is CustomActivity.
Then I add a new class that has got an attached property, example below:
public class AttachedObject : DependencyObject
{
public static readonly DependencyProperty NameProperty = DependencyProperty.RegisterAttached(
"Name",
typeof(string),
typeof(AttachedObject),
new FrameworkPropertyMetadata(
string.Empty,frameworkPropertyMetadataOptions.AffectsRender));
public static void SetName(ContentControl element, string value)
{
element.SetValue(NameProperty, value);
}
public static string GetName(ContentControl element)
{
return (string)element.GetValue(NameProperty);
}
}
The last step is to change MainWindow class that way:
public MainWindow()
{
InitializeComponent();
var activity = new CustomActivity();
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1;assembly=WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ContentControl wpfApplication1:AttachedObject.Name="MainArea"/>
</Grid>
</Window>
The problem is it doesn't compile because of below error:
Error 1 The type or namespace name 'CustomActivity' could not be found (are you missing a using directive or an assembly reference?) WpfApplication1\MainWindow.xaml.cs 13 32 WpfApplication1
CustomActivity has a default namespace. In obj folder there is CustomActivity.g.cs generated, so I have no idea what's going on.
It's 100% reproducible. When I remove using of CustomActivity or using of AttachedObject from xaml then the problem disappear.
Try replacing this:
xmlns:wpfApplication1="clr-namespace:WpfApplication1;assembly=WpfApplication1"
with this
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
The error you're seeing is due to a "known" issue in WPF applications that xaml namespaces that reference clr namespace from current assembly your in don't require the full assembly qualified name. If you were to declare a xaml namespace that references a clr namespace from another assembly, than you would have to specify the full name (with the ;[assemblyname] syntax).
Workflow Foundation has nothing to do with it.
EDIT:
Didn't realize it was a xaml activity.
But still, you can make it work, maybe, with a few hacks, but I wouldn't recommend it.
The reason you get that error is due to the different code generation and build action VS uses when creating xaml artifacts for WPF (Page):
System.Windows.Application.LoadComponent(this, resourceLocater);
and when creating xaml activities (XamlAppDef):
typeof(CustomActivity).Assembly.GetManifestResourceStream(resourceName);
If you turn your CustomActivity xaml build action to Page, the whole thing will compile - but i'm guessing something else might be broken someplace else...or not, who knows. My guess is that these two kinds of xaml were not meant to live together in a VS WPF application project template. But you can still define activities in a WF activity library, that way your activities will also be more easily reusable for other projects, WPF, console or even services.
I have the same issue under Visual Studio 2017.
The problem in my case is that Visual Studio is not compiling the Workflow activities before the code that use them.
To fix it, what I did is to move all workflows to other project dll, so visual Studio is forced to compile the workflows before the classes that make use of them.
Does anyone know of some global state variable that is available so that I can check if the code is currently executing in design mode (e.g. in Blend or Visual Studio) or not?
It would look something like this:
//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode)
{
...
}
The reason I need this is: when my application is being shown in design mode in Expression Blend, I want the ViewModel to instead use a "Design Customer class" which has mock data in it that the designer can view in design mode.
However, when the application is actually executing, I of course want the ViewModel to use the real Customer class which returns real data.
Currently I solve this by having the designer, before he works on it, go into the ViewModel and change "ApplicationDevelopmentMode.Executing" to "ApplicationDevelopmentMode.Designing":
public CustomersViewModel()
{
_currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}
public ObservableCollection<Customer> GetAll
{
get
{
try
{
if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
{
return Customer.GetAll;
}
else
{
return CustomerDesign.GetAll;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
I believe you are looking for GetIsInDesignMode, which takes a DependencyObject.
Ie.
// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);
Edit: When using Silverlight / WP7, you should use IsInDesignTool since GetIsInDesignMode can sometimes return false while in Visual Studio:
DesignerProperties.IsInDesignTool
Edit: And finally, in the interest of completeness, the equivalent in WinRT / Metro / Windows Store applications is DesignModeEnabled:
Windows.ApplicationModel.DesignMode.DesignModeEnabled
You can do something like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
public static bool InDesignMode()
{
return !(Application.Current is App);
}
Works from anywhere. I use it to stop databound videos from playing in the designer.
There are other (maybe newer) ways of specifying design-time data in WPF, as mentioned in this related answer.
Essentially, you can specify design-time data using a design-time instance of your ViewModel:
d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"
or by specifying sample data in a XAML file:
d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">
You have to set the SamplePage.xaml file properties to:
BuildAction: DesignData
Copy to Output Directory: Do not copy
Custom Tool: [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]
I place these in my UserControl tag, like this:
<UserControl
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignWidth="640" d:DesignHeight="480"
d:DataContext="...">
At run-time, all of the "d:" design-time tags disappear, so you'll only get your run-time data context, however you choose to set it.
Edit
You may also need these lines (I'm not certain, but they seem relevant):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
When Visual Studio auto generated some code for me it used
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
...
}
And if you extensively use Caliburn.Micro for your large WPF / Silverlight / WP8 / WinRT application you could use handy and universal caliburn's Execute.InDesignMode static property in your view-models as well (and it works in Blend as good as in Visual Studio):
using Caliburn.Micro;
// ...
/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
if(Execute.InDesignMode)
{
//Add fake data for design-time only here:
//SomeStringItems = new List<string>
//{
// "Item 1",
// "Item 2",
// "Item 3"
//};
}
}
Accepted answer didn't work for me (VS2019).
After inspecting what was going on, I came up with this:
public static bool IsRunningInVisualStudioDesigner
{
get
{
// Are we looking at this dialog in the Visual Studio Designer or Blend?
string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
return appname.Contains("XDesProc");
}
}
I've only tested this with Visual Studio 2013 and .NET 4.5 but it does the trick.
public static bool IsDesignerContext()
{
var maybeExpressionUseLayoutRounding =
Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
return maybeExpressionUseLayoutRounding ?? false;
}
It's possible though that some setting in Visual Studio will change this value to false, if that ever happens we can result to just checking whether this resource name exist. It was null when I ran my code outside the designer.
The upside of this approach is that it does not require explicit knowledge of the specific App class and that it can be used globally throughout your code. Specifically to populate view models with dummy data.
I have an idea for you if your class doesn't need an empty constructor.
The idea is to create an empty constructor, then mark it with ObsoleteAttribute. The designer ignores the obsolete attribute, but the compiler will raise an error if you try to use it, so there's no risk of accidentaly using it yourself.
(pardon my visual basic)
Public Class SomeClass
<Obsolete("Constructor intended for design mode only", True)>
Public Sub New()
DesignMode = True
If DesignMode Then
Name = "Paula is Brillant"
End If
End Sub
Public Property DesignMode As Boolean
Public Property Name As String = "FileNotFound"
End Class
And the xaml:
<UserControl x:Class="TestDesignMode"
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:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
mc:Ignorable="d"
>
<UserControl.Resources>
<vm:SomeClass x:Key="myDataContext" />
</UserControl.Resources>
<StackPanel>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
</StackPanel>
</UserControl>
This won't work if you really need the empty constructor for something else.