WPF: use the same xaml file with different codebehinds - c#

I'm writing a wpf program that needs several usercontrols that look exactly the same but perform different functions. With winForms, I could just extend the base control and add the functionality, but as far as I know, it's impossible to inherit xaml files. Is there any way I can have different codebehind classes that all use the same xaml file for their control?

You might be able to do this using MVVM pattern and create multiple VMs which perhaps implement the same interface. The XAML view could then be bound to any of your VMs relying on the fact they share the same interface.
In this approach you'd not use the code behind at all.

One way to do it is by using inheritance. A very simple example would be a UserControl with a single button, that should display different contents in a MessageBox.
We will have something like this:
public abstract class SomeUserControl : UserControl
{
//declared by XAML (can be made public with x:FieldModifier="public")
public Button MyButton;
//code-behind
public SomeUserControl() {
InitializeComponent();
}
}
public class MySpecialControl : SomeUserControl {
public MySpecialControl() {
MyButton.Click += (sender, e) => MessageBox.Show("Bla");
}
}
To use the MySpecialControl, just declare it in XAML like you did with your previous one:
<myNamespace:MySpecialControl />
Note that you can also create an abstract method for the button click, if the variation in behavior is not so big.

With winForms, I could just extend the base control
And one can't do similar in WPF?
Create a custom composite control with a dependency property(ies) which would set the mode of the control to fit its the target consumer's needs.
The control could be based on an existing control or controls.

Related

How to make a XAML view (a page) inherit from a class, that uses UserControl as generic type

I have an issue, and I don't know if I can do that, or if there is another way to do that. I have an abstract class called "BasePage", it is my .NET Standard library, so I can't access to System.Windows namespace. Its declaration is:
public abstract class BasePage<VR> where VR : new()
EDIT: The class above has a public property to access to VR
So now, for each platform (WPF, Xamarin, etc) I have to create its own implementation of the class begin VR the content control of each platform (UserControl for WPF, for example). I already did it and this is:
public class WindowsBasePage : BasePage<UserControl>
Now, every time I want to create a page to add content to a window, I have to create something like this:
public partial class UserPassPage : WindowsBasePage
{
public UserPassPage()
{
InitializeComponent();
}
}
The problem becomes when I have to set it in the XAML file (the View). I can create it and it builds:
<local:WindowsBasePage x:Class="Bitture.AppManager.Manager.UserPassPage"
[...]
xmlns:local="clr-namespace:Bitture.AppManager.Manager"
mc:Ignorable="d" >
</local:WindowsBasePage>
but I can't add components (like buttons, text, grids, stackpanels, etc). I want to know If I can do it with my current code or there is something I have to change. Because I have to access to the generic type WindowsBasePage that inherits from
class WindowsBasePage : BasePage<UserControl>
I am not sure what you are trying to do here but you can't add UIElements to a custom class of yours that doesn't inherit from any of the common WPF base classes such as for example Panel or ContentControl, and expect it to be rendered as a UserControl or some other WPF control.
This won't work. WPF knows about how to render WPF controls but it doesn't know how to render a custom BasePage<UserControl>.

C# Custom Control Properties

I am building some applications that use OPC to control some industrial automation. I have decided it might be a good idea to create some custom controls for standard things I will use such as buttons and text boxes. One of my main reasons was that I felt in an ideal pattern the end object i.e. the button is the one who holds information about the OPC item it refers to otherwise in a typical application my Form class gets polluted by tons of variables that are in my mind scoped more global then they should. I started then by using the Tag property of the button but this requires some overhead code that is the same for each instance. I felt like the right thing to do is subclass controls that I would like to use and provide properties to configure each one.
With that context in mind my real question is this. To make it as portable as possible I decided there should a property to define the OPC Group. I declared a property like this
public class OPCButton : Button
{
[Category("OPC")]
public OPCConnectedGroup
{
get { return _OPCGroup; }
set { _OPCGroup = value; }
}
}
This shows up int the property list when I add the control but I am unable to bind this property even though my Form1 contains
public OPCConnectedGroup Connection1 = new OPCConnectedGroup();
I have resolved that the way to solve this is to probably create an additional control like OPCGrp that can be added to a Form then the Controls can reference this. To test I added a property of type Button and sure enough when I added it and browsed to the property it gave me options for all the buttons on the Form. I have no huge problems with this approach I just want to make sure that Im following a prototypical pattern because I will be responsible for maintaining the control library but not always implementing and Im trying to get it down to a 1-2 step process to implement a control.
Thanks
Matt
When defining OPCConnectedGroup you can inherit Component class.
This way if you have a property of type OPCConnectedGroup in your OPCButton, then at design time, you can put instances of OPCConnectedGroup on the form, and then if you choose your OPCButton at designer, that property of type OPCConnectedGroup will show as a drop down list that you can select one of instances that you put on the form for it.
Example:
If I have such MyButton and MyClass:
public class MyButton : Button
{
public MyClass MyClassInstance { get; set; }
}
public class MyClass : Component
{
public string SomeProperty {get;set;}
}
Then you can put some (or one) instance of MyClass on the component tray of the form:
And then if you select MyButton on your form, you can choose one of MyClass instances from in property grid:

Specify properties from baseform towards inherited ones

I have a c# winform that is a template for all the forms in my project.
My problem is how do I setup some properties for the controls that will be added in the inherited forms from the baseform.
For example I want all the textboxes that will be in the forms to have a specific color, or call an extension method.
Right now I tried the simple idea that popped out:
foreach (Control c in Controls)
{
if(c is ComboBox)
{
//do something
}
if(c is TextBox)
{
//do something
}
}
I put this code in the base form load event, but with no luck. I tried changing the modifiers from the inherited form to protected, but with no luck.
Is there any solution to this problem? Or I am obliged to put this code in all of my forms that inherit baseForm?
Custom Controls are the solution to the problem you have at hand. Simply extend existing Controls to have attributes of your desire and then you could these controls in all of your Forms.
You're beginning to think along the right lines, but you're not quite there yet. The solution to this problem is definitely object-oriented inheritance, but you must be careful not to violate other important principles of OOP, namely encapsulation.
To put things a different way, the form should not be required to "know" about the properties of the controls that it contains. It shouldn't know or care that it contains a ComboBox or a TextBox or a ListView.
Instead, you should subclass each of the child controls that you want to modify, and set their default properties there. Then, you would just add an instance of your custom subclassed control to your form, rather than the built-in control.
So, for example, your custom TextBox class might look like this:
public class CustomTextBox : TextBox // inherit from TextBox
{
public CustomTextBox()
{
// default constructor
}
// other logic...
}

Inheritance in WPF

I want to have the WPF controls inherited like this,
public class BaseView : UserControl
{
...
}
public class BaseListView : BaseView
{
...
}
public class TeachersListView: BaseListView
{
}
public class StudentsListView : BaseListView
{
}
Here "BaseListView" is the base classed. This classes may have several functionalities which depends on the ListView present in "BaseListView". I want to inherit this "BaseListView" to several views which may add several column's and with different databindings. So my requirement is
class BaseListView : BaseView
{
This class will have the UI parts like commandStrip and followed by "Empty ListView".
This "ListView" may not hold any columns in it.
}
class StudentsListView: BaseListView
{
In **XAML** part, Columns and its appropriate Data Binding will be added. I need to access the controls in .cs file. so that i can access the controls.
void FindAndHighlightColumn()
{
// get the columns to find and search the list view and highlight.
}
}
How can i achieve this, what is the right way to do this.
I think you want to create a UserControl (Items- or ContentControl) with some basic functionality like FindAndHighlightColumn().
You can create your BaseListView "lookless" and then use ControlTemplates to get several flavours of it (create styles like "StudentListViewStyle" etc., each with an appropriate ControlTemplate). A ControlTemplate is a view, so you can specify different bindings in each template, to access controls by their names you need to define a convention with certain parts named 'PART_XY' etc., look at the standard ProgressBar-Control for an example.
Are you using Model-View-ViewModel architecture? After reading your question, my initial thought is that I would not use inheritance to the extent you are thinking of. Instead, I would consider composition.
For example, could you create a composite StudentsListView by composing a .xaml file of multiple user controls? Maybe a user control to display your commandStrip and another user control to display the appropriate ListView (e.g. StudentListViewUserControl, TeacherListViewUserControl, etc.).

How can I easily keep consistent UI settings in C# Winform application?

I have a lot of different UserControls and would like to maintain consistent UI settings (mainly colors and fonts). My first try was this:
public class UISettings
{
//...
public void SetupUserControl(ref UserControl ctrl)
{
ctrl.BackColor = this.BackColor;
}
}
to be called in every control like this:
settings.SetupUserControl(ref this);
As this is read-only it cannot be passed by ref argument so this does not work. What are other options to keep consistent UI without manually changing properties for every item?
Inheritance! If you have a form or control that will constantly be using the same styles and you want to set that as your base, just create your own user controls that inherit from a form/control. By default all of your forms will inherit from "Form". Instead of inheriting from the default form, create a new user control that inherits from Form, and then have that as your base class.
CustomForm : Form // Your custom form.
Form1 : CustomForm // Inherit from it.
...the same works for components. If you want a button to have the same styles across the board, create a user control and have it inherit from the button control -- then use the custom control.
Whenever you want to make a change to your base styles, or any settings, simply change your custom controls settings -- your new forms/controls will automatically be updated!
Do the same thing. Don't pass it by ref. UserControl is a reference object already, so there's no need to pass it into your method using the ref keyword.
You may also want to consider a recursive method that will find all the UserControls on the form and pass it into your method.
How about a base class which provides such settings?
Two answers:
You don't need ref, controls are objects are reference types. Just drop it.
Create a Base UserControl and derive your controls form that base. You can still do that, just edit the class definitions of the controls. For new controls you can follow the Wizard.
A tip: setup the styling in the baseControl. Then make sure the derived controls don't override, the best way to do that is scanning the *.Designer.cs files and remove all settings that you know should come from the base.

Categories

Resources