Понимание WPF, выводящего класс WIndow - PullRequest
13 голосов
/ 24 августа 2011

Я уверен, что это легко, но для меня это ново для WPF, использующего C #.Я знаю о наследовании от классов и делал так много раз, например, в проектах C # WinForms ...

public class MyClass : DerivedFromClass
{}

Однако, в тупик в WPF и вот проблема.Я хочу создать свой собственный набор элементов управления, которые будут использоваться в качестве основы для нового учебного проекта ... предустановите свои собственные стили, цвета, фоны и другие функции.Нет проблем.Сначала начните с окна WPF и создайте «MyWindow».

Теперь я хочу взять эту базовую линию «MyWindow» и подкласс THAT для еще одного класса MySubClassedWindow.Итак, я создаю новый класс Window, и по умолчанию VS2010 создает как конструктор, так и части кода формы.Я делаю просмотр кода на MySubClassedWindow и нахожу

partial class MySubclassedWindow : Window
{}

В C # с использованием WinForms, я просто изменил бы на (и я включил ссылку на библиотеку классов, которая включает в себя объявление "MyWindow".

partial class MySubclassedWindow : MyWindow
{}

Когда я это делаю, я получаю ошибку компиляции

Partial declarations of 'MyNameSpace.MySubclassedWindow' must not specify different base classes

Ответы [ 2 ]

34 голосов
/ 24 августа 2011

Ваш базовый класс должен быть просто файлом класса (не Window).

Поэтому создайте WindowBase.cs

public class WindowBase : Window
{
    // ...
}

В MainWindow (например) измените xaml.файл cs для наследования от WindowBase

public partial class MainWindow : WindowBase
{
    public MainWindow()
    {
        InitializeComponent();
    }
    // ...
}

В MainWindow.xaml включите пространство имен для WindowBase и измените Window на base: WindowBase, например,

<base:WindowBase x:Class="SubclassWindow.MainWindow"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:base="clr-namespace:NamespaceForWindowBase"
                  Title="MainWindow" Height="350" Width="525">
    <!--...-->
</base:WindowBase>
3 голосов
/ 04 апреля 2016

Наличие базового класса Window приносит критический недостаток, а именно то, что связывание со свойствами в вашем базовом классе сделать намного сложнее (и принятый в настоящее время ответ не решает эту проблему) . Какой смысл наследовать, если вы не можете ссылаться на базовые свойства? Я выяснил, как это настроить после нескольких долгих часов, и хотел поделиться надеждой, что другие избавятся от этой боли.

Возможно, вам потребуется использовать такие вещи, как преобразователи значений, на которые можно ссылаться только через статическое связывание, которое в моем случае имело смысл иметь в классе WindowBase. Я включил пример, потому что мне было трудно использовать эти преобразователи последовательно как в режиме разработки, так и в режиме работы.

Вы не можете установить свойство x: Name этого унаследованного окна с помощью XAML, но вам может не потребоваться это делать, если используется описанный ниже подход. Я включил пример того, как установить имя, потому что наследование от Window не позволит вам установить имя во время разработки в подклассе. Я не рекомендую полагаться на имя окна во время разработки, но настройка d: DataContext должна позаботиться о любых связывающих вас потребностях.

Имейте в виду, что в режиме разработки, но не в режиме выполнения, экземпляр WindowBase (или класс, указанный в d: DataContext) будет создан в режиме разработки и использован в качестве контекста привязки. Таким образом, в очень специфических случаях вы можете увидеть несоответствия данных, но в подавляющем большинстве случаев использования этого подхода должно быть достаточно.

WindowBase.cs

`` ``

public class WindowBase : Window
{
    //User-Defined UI Configuration class containing System.Drawing.Color 
    //and Brush properties (platform-agnostic styling in your Project.Core.dll assembly)
    public UIStyle UIStyle => Core.UIStyle.Current;

    //IValueConverter that converts System.Drawing.Color properties 
    //into WPF-equivalent Colors and Brushes 
    //You can skip this if you do not need or did not implement your own ValueConverter
    public static IValueConverter UniversalValueConverter { get; } = new UniversalValueConverter();

    public WindowBase()
    {
        //Add window name to scope so that runtime properties can be referenced from XAML
        //(Name setting must be done here and not in xaml because this is a base class)
        //You probably won't need to, but working example is here in case you do.
        var ns = new NameScope();
        NameScope.SetNameScope(this, ns);
        ns["window"] = this;

        //Call Initialize Component via Reflection, so you do not need 
        //to call InitializeComponent() every time in your base class
        this.GetType()
            .GetMethod("InitializeComponent", 
                System.Reflection.BindingFlags.Public | 
                System.Reflection.BindingFlags.NonPublic | 
                System.Reflection.BindingFlags.Instance)
            .Invoke(this, null);

        //Set runtime DataContext - Designer mode will not run this code
        this.DataContext = this;
    }

    //Stub method here so that the above code can find it via reflection
    void InitializeComponent() { }
}  

SubClassWindow.xaml

<local:WindowBase
        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:YourProjectNamespace"
        x:Class="YourProjectNamespace.SubClassWindow"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type= {x:Type local:WindowBase}, IsDesignTimeCreatable=True}"
        Title="SubClassWindow" Height="100" Width="300">
    <!--Design-time DataContext is set in d:DataContext. That option does not affect runtime data binding
        Replace local:WindowBase with local:SubClassWindow if you need to access properties in SubClassWindow-->
    <Grid Background="{Binding UIStyle.BackgroundColor, Converter={x:Static local:WindowBase.UniversalValueConverter}}"></Grid>
</local:WindowBase>

Ничего не требуется в коде SubClassWindow (даже в конструкторе).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...