Where does the code for WPF a window/usercontrol resource go? - c#

I'm trying to follow this tutorial, but I'm not clear on where the code for the EnumMatchToBooleanConverter class is supposed to go. I assumed that it would go in the code-behind file (i.e. view.xaml.cs), but then I get an error along the lines of The type EnumMatchToBooleanConverter was not found when I try declaring the resource in the XAML.

In general, a small WPF project should have the following approximate folder structure:
ProjectName
Converters
DataAccess
DataTypes
Images
ViewModels
Views
Converters is the folder where you should store your Converter classes. After developing WPF for a while, you'll find that your collection of Converter classes will increase in size. Each of these folders contain classes that we map to related namespaces. In the case of the Converter classes, it would typically be like this:
namespace ProjectName.Converters
{
[ValueConversion(typeof(bool), typeof(Brush))]
public class BoolToBrushConverter : IValueConverter
{
...
}
}
For the DataTypes classes, you'd use something like:
namespace ProjectName.DataTypes
{
public class SomeDataType
{
...
}
}
As #LordTakkera correctly mentioned, you'd then need to reference these classes in XAML by defining a XAML namespace like so:
xmlns:Converters="clr-namespace:ProjectName.Converters"
Then you could define the Converter in the Resources section like this:
<Converters:BoolToBrushConverter x:Key="BoolToBrushConverter" />
See the Data Conversion section of the Data Binding Overview page on MSDN for more information. The IValueConverter interface page on MSDN is another useful resource.

EnumMatchToBooleanConverter in this case is its own class. You should be able to declare it in a existing code behind, but I would stick it into its own file just to be sure.
Visual Studio can be dumb when finding resources, so you should rebuild the project in case errors are still shown.

Converters (like all other classes) belong in their own file.
Then, you just need to include the namespace in your XAML:
xmlns:local="clr-namespace:MyNamespace"
Also, try rebuilding/running the app as the XAML "intellisense" often won't update what is in the namespaces until a build has taken place.

Related

Having my Viewmodel appear in namespace dropdown

I'm trying to expose the ViewModel as a static resource on the page so that it can be easily accessible by the binding.
TestViewModel.cs
namespace Test.WPFUI.Home
{
public class TestViewModel....
HelloWorldView.Xaml
xmlns:local="clr-namespace:Test.WPFUI.Home"
<UserControl.Resources>
<local:TestViewModel x:Key="mainPageViewModel" />
</UserControl.Resources>
TestViewModel Can't be found. May I ask for some tips or suggestions Please.
Getting help from http://www.telerik.com/help/silverlight/gridview-troubleshooting-blank-cells.html
public class LoanViewModel : ScreenViewModelBase<LoanViewModel>, IRecord, INotifyPropertyChanged
{
public LoanViewModel(IEventAggregator events) .............
It sounds like your initial problem was not having the full xmlns definition. You usually need both the namespace and assembly.
The easiest way to get it right, in my experience, is to let intellisense do it for you. Just start typing the namespace you want, and as long as its in a referenced project, there will be an autocomplete option.
Your second problem is due to not having a default constructor. You wrote this:
<local:TestViewModel x:Key="mainPageViewModel" />
Which will invoke the default constructor. However, you define a constructor here:
public LoanViewModel(IEventAggregator events) .............
Which removes the provided (paramaterless) default constructor. I'm going to take a wild guess and say that creating the correct IEventAggregator is not simple or desired from XAML, so I see two choices:
You didn't really need that parameter in the constructor. Simply add a default constructor to your view model and you are good to go!
You really need that parameter, so instantiating from XAML just isn't a good idea. Pass in your view model from somewhere else on the view's constructor.
If you feel like you can instantiate the correct object from XAML, use this post to invoke the paramaterized constructor: Calling a parameterized constructor from XAML
In my opinion, putting truly regular classes into XAML is not a good pattern to follow, so I wouldn't. By regular, I mean not related at all to the view.

Alias to static class in XAML

For localization I have one resx file per XAML file. They lie in the same directory and namespace. The resx name corresponds to the XAML name with the word Resources appended.
I access the resources like this:
<TextBlock Text="{x:Static r:MainWindowResources.SomeText}"/>
Since I find this quite lengthy (and there are even longer class names) I was wondering if there was some way I could define an alias to MainWindowResources. In C# I can do this with a using directive.
It would be a lot easier if the generated resource file wrapper wouldn't be a class with static properties. A possible solution would be to use a wrapper instance which inherits from DynamicObject. You could pass it a type and access the type's static members through it. Then you'd add an instance of this wrapper as a resource in XAML.
But I'd lose IntelliSense support and it probably wouldn't be great performance-wise either.
Another solution would be to use the WPF Localization Extension but I'd also lose IntelliSense support. Plus I'm curios whether there is any other way to create an alias to a static class. :)
No, there is no way to simply alias the class name in Xaml like you would in C# with using.
A custom markup extension with a short name is probably the best you could do, but as you say, you would lose editor completion support. If you're really desperate, you could write a T4 template that would generate an enum with one value for each string in your resource file, and then you could use an enum value as your markup extension parameter with completion support (e.g., {l:MainWindowString SomeText}), but that seems like a lot of work just to shorten some Xaml attributes, and they wouldn't be that much shorter.
I would just stick with what you have.

Access created UI Elements in XAML WPF

I Have
class Canvas2:Canvas
{
}
class created in the same namespace. i can't use Canvas2 in XAML.
how can i make Canvas2 accessable in XAML code?
Im a newby.
Define the xmlns like xmlns:local="clr-namespace:WpfApplication1" assuming Canvas2 is define in namespace WpfApplication1.
then you can use Canvas2 as <local:Canvas2 x:Name="MyCanvas"/>
Thanks
you have to import your local namespace to the XAML too.
Check the MSDN for sample.
A quick and dirty answer: Add the following line to your AssemblyInfo.cs
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "YourNamespace")]
This way you add all classes in your Namespace to the default WPF-XML-Namespace. Then you can use your classes directly without adding an custom xml namespace.
Warning: Even if this works, it is not the recomended way. Especially I would not recommend this for larger projects because it could easily lead to name conflicts.
The correct way is to add a custom XML namespace like nit and AsitK described.

Fix embedded resources for a generic UserControl

During a refactoring, I added a generic type parameter to MyControl, a class derived from UserControl. So my class is now MyControl<T>.
Now I get an error at runtime stating that the embedded resource file MyControl`1.resources cannot be found. A quick look with .NET Reflector shows that the resource file is actually called MyControl.resources, without the `1.
At the start of the MyControl<T>.InitializeComponent method there is this line which is probably the one causing problems:
System.ComponentModel.ComponentResourceManager resources =
new System.ComponentModel.ComponentResourceManager(
typeof(MyControl<>));
How do I force the ComponentResourceManager to use the embedded resource file MyControl.resources? Other ways to resolve this issue are also welcome.
Turns out you can override the resource filename to load by inheriting from ComponentResourceManager like this:
using System;
using System.ComponentModel;
internal class CustomComponentResourceManager : ComponentResourceManager
{
public CustomComponentResourceManager(Type type, string resourceName)
: base(type)
{
this.BaseNameField = resourceName;
}
}
Now I can make sure that the resource manager loads MyControl.resources like this:
System.ComponentModel.ComponentResourceManager resources =
new CustomComponentResourceManager(typeof(MyControl<>), "MyControl");
This seems to work.
edit: the above line is overwritten if you use the designer, because it is in the
generated code region. I avoid the designer and make use of version control tools to revert any unwanted changes, but the solution is not ideal.
In addition to Wim's technique, you can also declare a non-generic base control that has the same name as your generic class, and have your generic control/form derive from that non-generic base class.
This way you can trick both the designer and the compiler into using the resource file from your generic class, and you get permanent designer support once the base class is setup without having to fiddle in the .designer file everytime you rebuild :
// Empty stub class, must be in a different file (added as a new class, not UserControl
// or Form template)
public class MyControl : UserControl
{
}
// Generic class
public class MyControl<T> : MyControl
{
// ...
}
The only requirements are to have exactly the same name for your generic class and its base class, and that the base class must be in another class file, otherwise the designer complains about not finding one of the two classes.
PS. I tested this with forms, but it should work the same with controls.
On my Visual Studio 2008 I have this error:
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MyControl));
Using the generic type 'WindowsFormsApplication1.UserControl1' requires '1' type arguments.
Notice that in my case code was generated without parentheses, <>, after the class name.
It is becoming interesting, see ImageList autogenerates non-compiling code in a Generic User Control.
What they said:
Posted by Microsoft on 7/6/2005 at 2:49 PM
This is an interesting bug. You've hit upon a generic scneario that we do not support in the Windows Forms designer. We will not be able to add support for this in the Whidbey (my note: Visual Studio 2008?) release. We will consider this for a future version. As a workaround, you can use the designer to create a none generic UserControl with a public Type property and then create a generic class that inherits from it and passes T into the base classes Type property.
I suppose this control cannot be designed in the Visual Studio forms designer either.
The simplest and easiest workaround is to make a dummy class for the autogenerated typeof(). You do not need to inherit from it or even expose it to the outside:
// Non-generic name so that autogenerated resource loading code is happy
internal sealed class GridEditorForm
{
}
(In my experience, the time required getting the designer to work around generics was not worth the ideal coolness generics can provide. I won't be using generic windows forms or controls again.)

What is a partial class?

What is and how can it be used in C#.
Can you use the same concept in Python/Perl?
A partial type (it doesn't have to be a class; structs and interfaces can be partial too) is basically a single type which has its code spread across multiple files.
The main use for this is to allow a code generator (e.g. a Visual Studio designer) to "own" one file, while hand-written code is put in another.
I've no idea whether Python/Perl have the same capabilities, I'm afraid.
The c# partial class has been already explained here so I'll just cover the python part. You can use multiple inheritance to elegantly distribute the definition of a class.
class A_part1:
def m1(self):
print "m1"
class A_part2:
def m2(self):
print "m2"
class A(A_part1, A_part2):
pass
a = A()
a.m1()
a.m2()
A partial class is simply a class that's contained in more than one file. Sometimes it's so that one part can be machine-generated, and another part user-edited.
I use them in C# when I'm making a class that's getting a bit too large. I'll put the accessors and constructors in one file, and all of the interesting methods in a different file.
In Perl, you'd simply have two (or more) files that each declare themselves to be in a package:
(main program)
use MyClass;
(in MyClass.pm)
use MyClassOtherStuff;
package MyClass;
# [..class code here...]
(in MyClassOtherStuff.pm)
package MyClass;
# [...rest of code here...]
The concept of partial types have already been explained.
This can be done in python. As an example, do the following in a python shell.
class A(object):
pass
obj = A()
def _some_method(self):
print self.__class__
A.identify = _some_method
obj.identify()
Because python is a dynamic language you don't need a concept like partial class. In python is possible to extend object with functionality in runtime so it possible to break class declaration into different files
A Partial type is a type whose declaration is separated across multiple files. It makes sense to use them if you have a big class, which is hard to handle and read for a typical developer, to separate that class definition in separate files and to put in each file a logically separated section of code (for instance all public methods and proprieties in one file, private in other, db handling code in third and so on..)
No you don't have the same syntactical element in Python.
Python also has meta classes but that is more like a template class than a partial class. A good example of meta class usage is the Django ORM. All of your table models inherit from a base model class which also gets functionality included from a meta class. It is a pretty cool concept that enables an active record like pattern (is it full active record?).
Partial class comes handy when you have auto-generated code by some tool. Refer question Project structure for Schema First Service Development using WCF for an example.
You can put your logic in the partial class. Even if the auto-generated file is destroyed and recreated, your logic will persist in the partial class.

Categories