2011-08-24 261 views
10

これは簡単ですが、C#を使用したWPFの新機能です。私は、WPFに困惑し、ここで問題です、しかし...WPF派生WIndowクラスを理解する

public class MyClass : DerivedFromClass 
{} 

をクラスから継承について知っていると、このようなC#のWinFormsのプロジェクトのように何度も行っています。自分のスタイル、色、背景、その他の機能をプリセットして、新しい学習プロジェクトのベースラインとして使用するための独自のコントロールセットを構築したいと考えています。問題ない。最初にWPFウィンドウを開き、「MyWindow」を作成します。

ここで、このベースライン "MyWindow"をとり、それをさらに別のクラスのMySubClassedWindowにサブクラス化したいと思います。したがって、私は新しいWindowクラスを作成し、デフォルトでVS2010はフォームのデザイナーとコード部分の両方を構築します。私はMySubClassedWindowにビューのコードを実行すると、リサイズを使用してC#では

partial class MySubclassedWindow : Window 
{} 

を見つけ、私はちょうどに変化するであろう(と私は「mywindowを」宣言を含んクラスライブラリリファレンスを用意しました。

partial class MySubclassedWindow : MyWindow 
{} 

私が行うとき、私はあなたの基底クラスがちょうどクラスファイル(ないWindow)でなければなりません

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

XAML(xaml.cs以外)の格闘はどのように見えますか? –

答えて

26

のコンパイル・エラーが発生します。

ので、(例えば)の代わりにWindowBaseからMainWindow.xamlで

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

を継承するxaml.csファイルを変更するメインウィンドウで

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

WindowBase.csを作成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> 
+0

うん...それはそれを行うだろう...どのように明白な(NOT)...また、私のBASEクラスの宣言は、すべてのコードでなければならないxamlを介してではなく、私はWinFormsの開発を行っていたとき、その部分が予想しやすくなりました。ありがとう – DRapp

+0

AppStartupイベントでFrameworkElement.StyleProperty.OverrideMetadata(typeof(Window)、 新しいFrameworkPropertyMetadata(TryFindResource(typeof(Window)));)を追加することを忘れないでください。それ以外の場合、派生クラスはデフォルトのウィンドウスタイルを使用しません – adrianm

+0

別の同様の質問からの素敵なブログ投稿リンク - [WPFでのベースウィンドウクラスの作成](http://weblogs.asp.net/psheriff/archive/2009/11/02 /creating-a-base-window-class-in-wpf.aspx) – akjoshi

3

ようWindowBase基本Windowクラスを有するとの結合、すなわちという、重大な欠点をもたらします(そして現在受け入れられている答えではこの問題は解決しません)あなたのベースクラスのプロパティははるかに難しいです。基本プロパティを参照できない場合、継承するポイントは何ですか?私は長い時間をかけてこれを設定する方法を考え出し、他の人がこの痛みを免れることを望みたいと思っていました。

私はWindowBaseクラスに持っているのが理にかなっていた静的バインディングを介してのみ参照できるバリューコンバータのようなものを使う必要があるかもしれません。私は例を挙げました。なぜなら、これらのコンバータを設計モードと実行モードの両方で一貫して使用することが困難であることがわかったからです。

XAMLを使用してこの継承されたウィンドウのx:Nameプロパティを設定することはできませんが、以下の方法を使用する場合は必要ありません。 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コード(もないコンストラクタ)に必要ありません。

関連する問題