I am designing a UI Library and I want to add two C# file to a XAML file so that in one file I can define only event Handler to be used in that Xaml file and in another file i can define some other UI related Style for controls. And i want my xaml file to have access to my both C# file class directly.
I am doing something like this using x:Class:
For example:
I want to add a MainWindow.cs file to my XAML file:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TemplateLibrary.MainWindow">
But unfortunately XAML supports for only one class to get added to my XAML. Is there some way to add multiple C# file to a XAML file.
I think in your case you need to look in the direction of MVVM, because the further complication of the project will cause some difficulties. You can create multiple ViewModel's for a one View. In the role of View may suit:
UserControl
DataTemplate
In the case of UserControl this class can be partial, which will complement the other class. In the case of DataTemplate can dynamically change the content depending on View type.
In addition, all styles of Control's must be contained in ResourceDictionary and merged into the App.xaml file.
It seems that the MainWindow code behind is already a partial class file, and therefore we could choose to place some members into additional cs files using the same partial class in the same namespace.
namespace TemplateLibrary
{
public partial class MainWindow : Window
{
...
The same applies when making a UserControl.
More basic is "How to bind an XAML visual object to code". Ranny Meier's suggestion on declaring my class on it's page as a 'partial class' coupled with (can't find him again) suggestion of using a redirection on the mainwindow page actually works fine - all in the same name space of course.
xaml
<Button x:Name="Pnl_Btn_EditPaste" Click="Do_Btn_EditPaste_Click" VerticalAlignment="Top" Padding="2" Margin="-67,18,0,0" ScrollViewer.VerticalScrollBarVisibility="Disabled" Width="36" Height="30" RenderTransformOrigin="1.976,-0.568">
<Button.OpacityMask>
<ImageBrush ImageSource="pack://siteoforigin:,,,/Resources/BnFace_paste.png"/>
</Button.OpacityMask>
<Button.Background>
<ImageBrush ImageSource="pack://siteoforigin:,,,/Resources/BnFace_paste.png"/>
</Button.Background>
</Button>
It's the "Click=" portion, or binding, on the Button opening statement we're interested in . . .
mainwindow c#
namespace WpfAppFoolAround
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// -- Edit Controls ---------------------------------------------------------
private void Do_Btn_EditPaste_Click(object sender, RoutedEventArgs e)
{
ContextControls.Btn_EditPaste(sender, e);
}
}
}
The shim on mainwindow to redirect us to the class method . . .
the class on a different page
namespace WpfAppFoolAround
{
public partial class ContextControls
{
// -- Edit Controls ---------------------------------------------------
internal static void Btn_EditPaste(object sender, RoutedEventArgs e)
{
Console.WriteLine("PASTE Editing Button Clicked.");
}
}
}
And the actual method located in the class on the odd project page we added.
Related
I am working on refactoring an application to use property injection. This has required me to create the views from the code behind like such. Originally everything was created in XAML and bindings were set to the view models by static resources. This gave no control over injecting the service for getting data into the view model.
This is the App.xaml.cs:
public App()
{
this.MainWindow = new MainWindow(new MainWindowViewModel(new DbDataService()));
MainWindow.Show();
}
MainWindowViewModel is set as the datacontext.
App.xaml contains this resource for viewing the product type class in a listbox:
<DataTemplate x:Key="DataTemplate" DataType="{x:Type classes:Product}">
The MainWindow has a tab for each view. I have a tab's view created like this in MainWindow's constructor:
ProductsTab.Content = new MainView(mainWindowViewModel);
When I do this, I get the following error in the MainView on this line:
<dxe:ListBoxEdit Grid.Column="0" ItemTemplate="{StaticResource DataTemplate}" ...etc... />
"'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '37' and line position '31'."
What I have tried:
I have tried creating the Tab's view in XAML and setting its data context to the parents, however, I still got this exception.
I have tried changing my static resources to dynamic resources, which causes no error at runtime, but the list box does not display the information correctly.
What I need to know:
How to use static/dynamic resources with decency injection.
If there is a better approach to this problem, such as creating the templates in code and injecting them into the views?
Some of my concerns:
I want to add dependency injection to this application, however, I feel like the approach I'm using not only breaks the resources but breaks the MVVM pattern.
Try to create and call your MainWindow in the OnStartup method of your App class:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.MainWindow = new MainWindow(new MainWindowViewModel(new DbDataService()));
MainWindow.Show();
}
}
This should work provided that you define the "DataTemplate" resource in your App.xaml (or in a ResourceDictionary that you merge from App.xaml).
In my tests, I've created a simple class like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Test
{
public class MyCustomWindow: Window
{
}
}
This class is compiled into a dll.
In another project, I tried to use this custom window, like this:
<Custom:MyCustomWindow x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Custom="clr-namespace:Test;assembly=Test"
Title="MainWindow" Height="600" Width="1210" WindowState="Maximized" >
<Grid Background="Blue">
<Button Content="Button" HorizontalAlignment="Left" Margin="457,212,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
This thing compiles with no errors, and works great when the custom window is opened by the "StartupUri" in the App.xaml file (that defines the first window loaded).
However, if I set other window to load in the StartupUri, and:
MainWindow m = new MainWindow();
m.Activate();
m.Show();
this.Close();
The CustomWindow will open, but without any content, without button and without the blue grid - and even without the title.
Any workaround? And what I need to do to open a Window with the same behavior of the StartupUri?
Edit:
I've noticed that the MainWindow (or any window derived from MyCustomWindow) simply cannot have the method InitializeComponent() in the constructor, because it does not exist in the context. Strangely, when using StartupUri, the contents are loaded normally without this.
Edit 2:
I think that the problem is occurring because I can't put the InitializeComponent() method in the MyCustomWindow. This explains why the MainWindow can be loaded normally into the StartupUri: it's loading directly from the xaml file, so it's parsing the content without the need of the InitializeComponent.
I starting to think about implement the IComponentConnector interface, but I have no idea how to do this.
Edit 3:
The code-behind of the file MainWindow.xaml.cs is:
using Test;
namespace TestingCustomWindow
{
public partial class MainWindow : MyCustomWindow
{
public MainWindow()
{
// Cannot use InitializeComponent here
}
}
}
pls add the new window using Visual Studio and
Replace :Window with :MyCustomWindow. You will get initializecomponent. You will hav to update window tag with your CustumWindow tag in xaml also
Adding it as answer so other can use it.
Thanks
I think the constructor has to look like this
public class MyCustomWindow: Window
{
InitializeComponent();
}
I see a number of other people asking about this error message in other questions, but I don't seem to understand enough about what's going on to fix this for myself. I created this error by having a WPF UserControl
public partial class EnterNewRequest : UserControl
But then later on I wanted to add a method to UserControl, so I used inheritance to stick it in there (can't use an extension because I need to override this method). But now my usercontrol is upset, and I'm not sure what in the xaml I need to change. The UserControl change block is in the namespace RCO_Manager. This is my xaml:
<UserControl x:Class="RCO_Manager.EnterNewRequest"
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"
I had the same issue when I was working with Windows Phone. I can't remember the exact exception, but you can see the XAML here on GitHub, the page code here, and the base page code here (mine was a base page, not base control). I needed to add a new XAML namespace and change the <UserControl/> declaration:
Code Assumption
namespace RCO_Manager
{
// Inherits **Base**UserControl, not UserControl
public partial class EnterNewRequest : BaseUserControl
{
// Magic goes here
...
}
}
XAML
<local:BaseUserControl
xmlns:local="clr-namespace:RCO_Manager"
x:Class="RCO_Manager.EnterNewRequest"
Side Note
According to Baboon, you don't need to specify it in your code-behind once you specify the base class in the XAML, so you can then change the code-behind to show the following. I can't verify it right now, but you can give this a try after you get it working.
public partial class EnterNewRequest // Don't specify BaseUserControl here
{
...
HOPEFULLY, someone strong in WPF knows what's going on... The scenario I've sampled below is also applicable to others too, like textbox, command buttons, etc...
I'm playing with creating custom user controls... Ex: working with a simple Combobox. In one project class library LibA I've created some samples derived from... ex: TextBox, ComboBox, Window, etc. A second library LibB I'm creating another class derived from ex: Combobox in LibA... Otherwise, no problem.... done similar thing in C# WinForms with no problems.
Now, the problem, I drag the control (from LibB) onto the first "Window" (native so no derivation issues) of the app, save and run. The derived library doesn't even hit its constructor which I just put a simple command just test it was getting created properly worked or not, but its not... In the XAML of the form, it is properly referencing both namespace projects, so I know that appears correct.
So, I then created a derived combobox in the same original LibA, put that on the form, and IT properly went into the constructor.
Here's a snippet of what I have going on.
namespace LibA
{
public class MyCombo1 : ComboBox
{
public MyCombo1()
{ ToolTip = "this is my base declaration"; }
}
public class MyCombo1b : MyCombo1
{
public MyCombo1b() : base()
{ ToolTip = "this constructor IS reached"; }
}
}
In a separate project (library),
using FirstLibraryThatHas_MyCombo1
namespace LibB
{
public class OtherLibCombobox : MyCombo1
{
public OtherLibCombobox() : base()
{ ToolTip = "this version is NOT being recognized in the window"; }
}
}
So, neither of these are visually designed, they are all in code only... In addition, I've done it with the TextBox control too, same results... It doesn't stop in the debugger... Any ideas?
Although I've changed actual names from sample, here's a brand new window, one with original class declaration AND one with the DERIVED version.. Here's a full XAML test window
<Window x:Class="MyProject.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="300" Width="300"
xmlns:my="clr-namespace:WPFGUI;assembly=WPFGUI"
xmlns:my1="clr-namespace:DerivedControls;assembly=DerivedControls">
<Grid>
<my:MyComboBoxClass
Name="MyComboBoxInWindow"
HorizontalAlignment="Left"
Height="23"
Width="120" />
<my1:cboDerivedComboClass
Name="cboDerivedComboInWindow"
Height="23"
HorizontalAlignment="Left"
Width="120" />
</Grid>
</Window>
Isn't this making a circular reference?
You call MyDerivedControl that is in another assembly, and DerivedControl needs the primary assembly
because it inherits a type you defined there.
And then, you try to display it in a window from the primary assembly?
Try to clean and rebuild your project.
I've tried and failed to reproduce the problem. I think you have a different problem, though. If you use the xaml above - the number two combobox will completely cover the first - thus you will not be able to get the tooltip...
Also, check that all assemblies target the same framework version.
I am trying to allow several classes to inherit a more general Silverlight user control to avoid redundancy in my code. The classes inherit the extended control, which then inherits the User Control class. The issue I have been running into is that the ExtendedControlExtension.g.cs file regenerates every time I compile, with the incorrect inheritance (it inherits User Control not my Extended Control).
Note that I have been inheriting the Extended Control in the .cs and g.cs files, but continuing to use the User Control tag in the .aspx file as this causes the error
Error 29 The tag 'ExtendedControl' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'.
Is there a way to fix this?
Thanks!
You cannot change the .g.cs file, in fact is says so right in the file. Also, it's unfortunate to use the term "custom control" as this means something specific and not what you are trying to do. But, the good news is that what you are trying to do is possible.
Derive from UserControl:
public class FancyUserControl : UserControl
{
// Your added common functionality.
}
and then add a new UserControl to your project using the normal mechanism, let's say UserControl1. Then edit the UserControl.xaml files as follows:
<local:FancyUserControl x:Class="SilverlightApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SilverlightApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
</Grid>
</local:FancyUserControl>
paying special attention to the three lines with local in them, adjusting to your application. Then edit the UserControl1.xaml.cs file as follows:
public partial class UserControl1 : FancyUserControl
{
public UserControl1()
{
InitializeComponent();
}
}
and Visual Studio won't be quite happy yet but finally rebuild your project and all will be well.
The class UserControl1 is now derived from FancyUserControl instead of UserControl and you can begin adding your common functionality. To add more controls you will need to manually edit the XAML and code-behind once after initially adding each new control to the project.