Inheriting from a UserControl in WPF - wpf

I am fairly new to WPF and I am having a problem with inheriting from a user control.
I created a User Control and now I need to inherit from that control and add some more functionality.
Has anyone does this sort of thing before? Any help would be greatly appreciated.
Thank you

Well .. you create your base control
public abstract class BaseUserControl : UserControl{...}
then in the XAML file :
<Controls:BaseUserControl x:Class="Termo.Win.Controls.ChildControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Namespace.Of.Your.BaseControl">
And that should work.
EDIT: Hmm.. this example is useful when you have a base control without XAML and then inherit from it. The other way around(from a base control with Xaml) - I'm not sure how you can go about it.
EDIT2: Apparently from this post + comments i take that what you want might not be possible.

AFAIK you cannot inherit the xaml, you can only inherit the code behind.
We recently encountered the same problem on our project. The way we ended up solving our problem was to create a usercontrol and adding it to the "child" usercontrol.
If that doesnt work/help take a look at this:
https://web.archive.org/web/20200815091447/http://geekswithblogs.net/lbugnion/archive/2007/03/02/107747.aspx[1]

I may have a bit of a solution: Composition instead of inheritance - I have come up with control, that has 'content slots' assignable from outside through databinding, look at my SO thread.
Example of use:
<UserControl ... >
<!-- My wrapping XAML -->
<Common:DialogControl>
<Common:DialogControl.Heading>
<!-- Slot for a string -->
</Common:DialogControl.Heading>
<Common:DialogControl.Control>
<!-- Concrete dialog's content goes here -->
</Common:DialogControl.Control>
<Common:DialogControl.Buttons>
<!-- Concrete dialog's buttons go here -->
</Common:DialogControl.Buttons>
</Common:DialogControl>
<!-- /My wrapping XAML -->
</UserControl>
Together with some handling code in codebehind it would be a nice base component for dialog windows.

You cannot inherit the xaml code it self. However creating an abstract class of the codebehind, will allow you to edit in code behind, from a derived class object.
Xaml Code: { Window1.xaml }
<Window
x:Class="WPFSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="auto" Width="256" Title="WPF Sameples">
<Grid>
<Button x:Name="Button1" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Click Me"/>
</Grid>
</Window>
CodeBehind: { Window1.xaml.cs }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFSamples
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public abstract partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
Derived Class : { DisabledButtonWindow.cs }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WPFSamples
{
public sealed class DisabledButtonWindow : Window1
{
public DisabledButtonWindow()
{
Button1.IsEnabled = false;
}
}
}
although you cannot inherit from the wpf source it self, you are able to use this "Window1" control as a template for all other derived controls.

You can accomplish this by using a delegate.
Essentially, you need to create an interface (YourInterface) which wraps up the functionality you want, then make both the user control and your class implement that interface.
Next, make sure the user control has a reference to an object of type IYourInterface, so that when your user control attempts to invoke a method of the Interface, it calls your class' method.
Because both the user control and class implement the same interface, they can be seen as the same kind of object - meaning you can put them both into a collection of objects of type IYourInterface. This should give you the behavior you want.
In ASP.NET I use this technique often, by having my classes inherit from abstract class ancestors. I don't understand why WPF doesn't support this. :(

I think that you can do this but that you will have to redefine any functions and possibly some other stuff that you reference in the xaml in the child class.
IE if you have a button click event that you subscribe to in the base class xaml you will need override the button click in the child class and call the base class button click event.
Not one hundred percent sure of the the details since it's my coworkers code that I'm drawing from but thought this would give a start to anyone looking to implement this in the future.

Related

"Help/Tutorial" page in WPF menu bar

I've added a menu bar to application, because I wanted to add there a little tutorial under "Help" menu. Like Help - > "How to use the program", that's the idea.
I would like this to be, a pop up window that has ability to include text, as well as photos to better explain the program. It should be able to have a little bit of formatting (just a simple spaces, tabulator, new lines) so the text with photos looks clean.
To sum up, I need an idea, a tutorial, a guide, an adivce - you name it what should I use to implement those things, because right now I am in a blank spot.
#edit Hope this clarifies my question.
To do this you need menu items:
<Window x:Class="WPFTestApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Menu>
<MenuItem Header="Help">
<MenuItem Header="How to use this program" Click="MenuItem_Click"></MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
And you would need a click handler:
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFTestApp2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
HelpWindow window = new HelpWindow();
window.Show();
}
}
}
Then, you would need to create a new window with all the help text you would like. You would need to design that window and I think that is really dependent on what the application does.

Add new contextmenu items to WindowsFormsHost which has default ContextMenu in WPF

We are using some ActiveX or windows form control which don't have the WPF equivalences, so naturally we use WindowsFormsHost to host these controls. We normally make an UserControl out of it with some general controls such as button to implement the common functionality. One piece of xaml code is something like this:
<WindowsFormsHost Name="windowsFormsHost1" >
<WindowsFormsHost.ContextMenu>
<ContextMenu>
<MenuItem Header="_Test1" />
</ContextMenu>
</WindowsFormsHost.ContextMenu>
<AxOWC:AxPivotTable x:Name="pivotTable" />
</WindowsFormsHost>
....
The AxPivotTable is a OWC (office web component) control. In another UserControl, we add a ReportViewer inside the WindowsFormsHost. Note that normally the AxPivotTable or ReportViewer has its default context menu even without any ContextMenu item I add.
So far my customized ContextMenu doesn't get showed yet (still the default one shows). Thanks to this question, I figured out I still need to capture the the mouse down event in the code-behind and set
windowsFormsHost1.ContextMenu.IsOpen = True
to show the contextmenu (weird though).
Now my problem is, only this Test1 ContextMenu is here now. The default ContextMenu won't show any more. As I mentioned, what we want is to add the customized on top of those default context menus.
this would be my working "Solution" for your example above i don't know if you need this also for Child Elements from your WindowsFormsHost. Hope this will help you
XAML
<Window x:Class="tete.MainWindow"
xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms">
<Grid>
<av:WindowsFormsHost Name="myWFH">
<wf:ComboBox Name="myCBox">
<wf:ComboBox.ContextMenu>
<wf:ContextMenu>
<wf:ContextMenu.MenuItems>
<wf:MenuItem Text="somet"/>
</wf:ContextMenu.MenuItems>
</wf:ContextMenu>
</wf:ComboBox.ContextMenu>
</wf:ComboBox>
</Grid>
</Window>
Code-Behind
using System.Windows;
using System.Windows.Controls;
namespace tete
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var child = myWFH.Child as System.Windows.Forms.ComboBox;
child.ContextMenu.MenuItems.Add(new System.Windows.Forms.MenuItem("my new menuitem"));
}
}
}
EDIT
i hope now it fit's your needs :) and i understand correctly what you want ToDo

WPF MVVM Implementation

I have just started using WPF with MVVM pattern. I had gone through some material related to MVVM.
However, the project I have to work on has an implementation of MVVM that seems very different than what I have read (maybe incorrect as well, not sure).
The implementation has all the Views (controls or windows) implemented as ResourceDictionary where all the controls, in the view are in the "Style" element.
The code behind for such ResourceDictionary have all the DependencyProperty and the Commands (there is no other class for ViewModel). Also, the classes (code behind) some how inherit from the Windows.Controls.Control class.
Is this the correct implementation ? If not what are the reasons that you see that prove this as a wrong implementation.
I may be wrong but the reasons I see are the following:
Implementing views as ResourceDictionary is not correct and Resources are not for creating custom views.
Having minimal code in the code behind is one of the important aspects of MVVM, that allows for loosely coupled architecture.
Since all views inherit from Windows.Controls.Control, writing unit test cases for the views would be difficult.
Am I correct or there are some other reasons that this implementation is incorrect (or am I wrong and this can be a way to implement MVVM in WPF).
Your views are highly appreciated.
Below is a sample code: (XAML)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Presentation"
>
<Style TargetType="{x:Type local:FirstControl}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FirstControl}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Height="490" DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="TEST TEXT" FontWeight="DemiBold"/>
<Button Command="{Binding Path=CloseCommand, Mode=OneTime}"
Width="48" Height="30"/>
</StackPanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code Behind:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
namespace Presentation
{
/// <summary>
/// View-model
/// </summary>
public class FirstControl : Control
{
static FirstControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FirstControl), new FrameworkPropertyMetadata(typeof(FirstControl)));
}
public FirstControl()
{
CloseCommand = new DelegateCommand(OnCloseCommand);
}
private void OnCloseCommand()
{
// Write code to close application.
}
public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(FirstControl));
public ICommand CloseCommand
{
get { return (ICommand)GetValue(CloseCommandProperty); }
set { SetValue(CloseCommandProperty, value); }
}
}
}
Hope this helps.
The DelegateCommand is a class to allow delegating command logic to methods passed as parameters.
The main point of MVVM is to allow each layer to be fully tested without the need of "higher" layers.
You should be able to test the Model, and in that test you should be able to successfully complete all the tasks required to send and retrieve data from your data store. Your model testing should not require any view or view-model to complete.
You should be able to test your View Model without the need for any UI code or other View level code. Your View Model should be able to logically do everything your application needs to do without any user interraction or UI code. Ideally, you should be able to test your ViewModel using mocked Model classes that provide predictable responses.

Silverlight: Does UserControl Have a Background Property?

I created a BarMenuItem UserControl in a Silverlight class library, and try to used in my main Silverlight application.
BarMenuItem.xaml:
<UserControl x:Class="ButtonControlLibrary.BarMenuItem"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
</UserControl>
BarMenuItem.xmal.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ButtonControlLibrary
{
public partial class BarMenuItem : UserControl
{
public BarMenuItem()
{
InitializeComponent();
}
}
}
So in the MainPage, I have xmlns:blib="clr-namespace:ButtonControlLibrary;assembly=ButtonControlLibrary" defined
Tried to use BarMenuItem:
<blib:BarMenuItem Width="100" Height="150" Background="Red"/>
Compile and run it, and I expected to see a Red background, but I see nothing.
What happenend?
I'm so confused. I googled a lot, finding there is a workaround, but very ugly: Put a Grid container inside the UserControl, and then binding its Background property to the UserControl's Background:
Background="{Binding Background, ElementName=guiUserControl}"
But this is not the solution. Please advice.
In Adobe Flex, it's so natural to change a UserControl's background like what I do in the above code.
Am I missing anything?
Thanks.
The property is there but it doesn't seem to work in Silverlight. Your next best bet is the solution you said you already know. Binding layoutroot's background with usercontrol's background.

Overspecified Namespace in UserControl fails WPF Build

I have a very simple user control, and I'm trying to instantiate it in XAML. I find that when I go a bit overzealous with the namespacing, I run into problems with x:Name.
Here is my UserControl:
<UserControl x:Class="UserControlTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300">
<Grid>
<Label Name="Label1">Label</Label>
</Grid>
</UserControl>
Here is the code-behind for the UserControl:
Namespace UserControlTest
Partial Public Class UserControl1
End Class
End Namespace
Now, note that I have the root namespace of my VB.Net project set to "UserControlTest". Knowing that, have a look at my main window:
Here is my main window:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control="clr-namespace:UserControlTest.UserControlTest"
Title="Window1" Height="300" Width="300">
<Grid>
<control:UserControl1 />
</Grid>
</Window>
See how the control alias needs to have "UserControlTest.UserControlTest"? That's because I have the root namespace of my project set to UserControlTest, and I have defined the namespace of the UserControl to be UserControlTest, also. If I don't use a namespace for the UserControl, I don't have any troubles.
However, because I have done this, the build fails should I try to apply an x:Name to the UserControl, as follows:
<control:UserControl1 x:Name="test"/>
That will fail the build, with this error:
Type 'UserControlTest.UserControlTest.UserControl1' is not defined.
Can anybody explain why? Do I need to avoid putting my UserControls into namespaces just so I can give them x:Name values? I'd like to manipulate my UserControls from code-behind, and without an x:Name, I'm up the creek. But I don't want to sacrifice namespace usage just to get it!
Thanks very much.
I had the same problem (after rebuilding the project, first it worked fine...). I put UserControl into separate namespace.
What is the namespace defined as in the code-behind of your user control?
If your project was called Foo and you had a folder called Controls inside that project, any new user control added to that folder would be given the namespace Foo.Controls.
Then in your XAML you can reference it like so:
xmlns:Controls="clr-namespace:Foo.Controls"
...
<Controls:UserControl1 x:Name="uc1"/>
It seems like you have a naming issue.
EDIT:
Here's how I'm doing it in a project of mine.
StatusBar.xaml.cs
namespace Client.Controls.UserControls
{
public partial class StatusBar : UserControl
{
...
}
}
StatusBar.xaml
<UserControl x:Class="Client.Controls.UserControls.StatusBar">
</UserControl>
Main.xaml.cs
using Client.Controls.UserControls;
namespace Client
{
public partial class Main : Window
{
...
}
}
Main.xaml
<Window x:Class="Client.Main"
xmlns:UserControls="clr-namespace:Client.Controls.UserControls">
<UserControls:StatusBar x:Name="mainStatusBar" />
</Window>
I encountered the same problem in a vb.net project, and despite trying the suggestions here and elsewhere, could not solve the issue. In fact, I was able to take the exact same code out of our project to a new project, and it worked just fine (as far as I could determine all the configuration in the new project was identical). In the solution provided by David, I notice he is using c# - I am wondering if this is some weirdness associated with vb.net.
In the end, the user control I needed to use was quite simple and I implemented it as a resource ControlTemplate to get around the issue. Sorry I don't have a better answer, I am really not happy wih my findings...

Resources