Creating an abstract base class for windows in WPF

2020-04-21 04:44发布

问题:

Usual WPF architecture:

public partial class MainWindow: Window {

... InitializeComponent()

}

XAML: <Window x:Class="MainWindow"> </Window>

What I want to move to:

public abstract class BaseWindow: Window {

    public System.Windows.Controls.TextBlock control1;
    public System.Windows.Shapes.Rectangle   control2;
    public System.Windows.Controls.TextBox   control3;

}

public partial class AWindowImplementation {

... InitializeComponent()

}

public partial class AnotherWindowImplementation{

... InitializeComponent() 

}

 XAML:
 <BaseWindow x:Class="AWindowImplementation"> </BaseWindow>
 <BaseWindow x:Class="AnotherWindowImplementation"> </BaseWindow>

The above is pseudo-code. This new architecture compiles, with warnings that the implementations hide the control defintions (because the place where I should put the 'override' keywords are withing the auto-generated InitializeComponent). Unfortunately the control fields don't get populated.

Is this achievable? What I am trying to do is create several UI designs with the same interface/controls so that the rest of the code can interact with either design.

EDIT: Thanks to pchajer and Yevgeniy, I now have the following working solution, but I still get override warnings:

 public class MainWindowBase : Window
 {
     public TextBlock control1;
     public Rectangle control2;
     public TextBox   control3;

    static MainWindowBase()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MainWindowBase),
                   new FrameworkPropertyMetadata(typeof(MainWindowBase)));
    }

    public override void OnApplyTemplate()
    {
        control1 = (TextBlock) FindName("control1");
        control2 = (Rectangle) FindName("control2");
        control3 = (TextBox)   FindName("control3");
    }

 }   

 <Style TargetType="{x:Type views:MainWindowBase}" 
           BasedOn="{StaticResource {x:Type Window}}">
     <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type views:MainWindowBase}">
                    <ContentPresenter />                                 
            </ControlTemplate>
        </Setter.Value>
     </Setter>
     </Style>

 public partial class AWindowImplementation :MainWindowBase {

 ... InitializeComponent()

}

 <MainWindowBase x:Class="AWindowImplementation"> </MainWindowBase>

I guess I will have to use different field names in the base class to get rid of the warnings, or perhaps remove InitializeComponent in the derived class. But anyway it works now.

回答1:

In WPF you can create a Base class which inherits from Window and that has a XAML. But there is a workground

refer this link - How to create a common WPF base window style?



回答2:

I'm not sure how you would expect that pseudo-code to work as nothing is calling your InitializeComponent. Ordinarily, WPF calls it on your behalf in your window's constructor. But in your case you're adding a new implementation (not an override) and nothing is calling it.

One option is to just call your new implementation from each subclass constructor. eg. AWindowImplementation's constructor could call this.InitializeComponent().

Another option is for BaseWindow to define a virtual method (say, InitializeComponentCore) that its constructor calls. Base classes can then override that method.



回答3:

You need to define base class for Window as a custom control. Just create a new custom control, set base class to Window and then insert style from blend (you may add yours components). See also answer from pchajer.