2

継承したいサードパーティからのWPFコントロールParentWPFControlがあります(子クラスChildWPFControlを呼び出しましょう)。その過程で、バックエンド ロジックの一部とフロント エンド スタイルの一部をオーバーライドする予定です。前者は問題なくできますが、後者は問題があります。

子国に xaml <-> xaml.cs 構造を使用しようとしましたが、VS から次の警告が表示されて許可されていないようです:

Partial declarations of 'ChildWPFControl' must not specify different base classes

ここで、ResourceDictionary XAML を記述してそこでフロント エンドを定義できると思いますが、XAML にイベント ハンドラーを追加する場合は問題になります (少なくとも、その方法は見つかりませんでした)。

私が持っている別の方法は、ChildWPFControl を使用するオブジェクトでオーバーライド テンプレートを直接定義することですが、これにより設計のモジュール性が低下します。

私が考えることができる最後の代替手段は、XAML スタイル コンテナーである xaml <-> xaml.cs ペアを作成し、ChildWPFControl がバックエンド イベント ハンドラーを介して内部で定義された ControlTemplate を使用するように強制することです。

とにかく、私が探しているのは、私の問題に対するエレガントでモジュラーなソリューションです。どんなアドバイスでも大歓迎です。

ありがとう

4

3 に答える 3

7

WPF コントロールを完全にオーバーライドするには、いくつかの手順が必要です。必要なものもあれば、必要に応じてオプションのものもあります。私はあなたのために2つの重要なものを説明します:

新しいデフォルト スタイルの作成

すべての WPF コントロールには、視覚的な表現とオーバーライド プロパティを含む既定のスタイルがどこかにあります。コントロールから派生した場合でも、WPF はこのデフォルト スタイルを使用したいと考えているため、このように静的コンストラクターで DefaultStyle を変更することを変更します。

class MyButton : Button
{
    static MyButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
    }
}

MyButton を使用すると、WPF は Button ではなく MyButton の Style を見つけようとします。OverridesDefaultStyle は、いくつかの点で便利なスタイルのプロパティです。通常、これらの既定のスタイルは、テーマに関連する xaml に配置する必要があります。

クラスをオーバーライドするときのイベント ハンドラー

ControlTemplateまたは、 の Styleようなイベントを使用する構文糖衣を使用できませんClick="OnClick"。ポイントは、ビジュアル表現がロジック部分から可能な限り分離されていることです。OnApplyTemplate メソッドを使用して、これを克服する方法は他にもあります。これをオーバーライドすることで、テンプレートに「このコントロールを渡してください」と要求し、そこにイベントを追加するだけです。

override OnApplyTemplate()
{
    var innerChild = Template.FindName("PART_InnerChild", this) as MyInnerControl;
    if(innerChild != null)
        innerChild.SomeEvent += OnSomeEvent;
}

注: これらのコントロールの名前は通常、慣例により PART_ で始まります。これは、WPF 基本コントロールにも見られます。設計者に「このコントロールがないと、ロジック部分が壊れる可能性がある」と伝える良い方法です。属性TemplatePartもありますが、それほど重要ではなく、WPF は気にしません。個人的には、このコントロールを機能させるためにどのような内部コントロールが絶対に必要かを他の人に伝えるために使用しています。

個人的なアドバイス

クラスからの派生は、通常、コントロールをカスタマイズしようとするときに行う最後のステップです。完全に機能させるには多くの作業が必要であり、再利用性が制限される可能性があるため、それを回避しようとしています。付属の動作

最後に、件名全体が素敵な MSDN記事でカバーされています。

それが役立つことを願っています

于 2013-06-19T17:46:43.543 に答える
2

ベース コントロールを含むユーザー コントロールをラッパーとして作成できます。このようにして、xaml でスタイルを変更し、ラップされた制御のために C# にいくつかのロジックを追加できます。しかし、それは面倒なプロセスです。

編集:サンプルの追加(telek:RadComboBox のラッパー)

XAML:

<UserControl x:Class="Controls.SingleDictionaryValueSelector"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:CardControls="clr-namespace:Controls"
             xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" MinWidth="150" MinHeight="25" >


    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="25"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <!-- customize visual for wrapped control -->
        <telerik:RadComboBox x:Name="cb" 
                            Grid.Column="0"
                            VerticalAlignment="Center"
                            SelectedValuePath="Key"        
                            ClearSelectionButtonContent="Clear"
                            ClearSelectionButtonVisibility="Visible"
                            CanAutocompleteSelectItems="True"
                            CanKeyboardNavigationSelectItems="True"
                            SelectAllTextEvent="None"
                            OpenDropDownOnFocus="false"
                            IsFilteringEnabled="True"
                            TextSearchMode="Contains"
                            EmptyText="Select item" 
                            telerik:StyleManager.Theme="Metro"
                            FontFamily="Calibri"
                            FontSize="14"
                            IsEditable="True"
                            Foreground="#666" 
                            KeyDown="cb_KeyDown"
                            SelectionChanged="cb_SelectionChanged"
                            GotMouseCapture="cb_GotMouseCapture" 
                            DropDownOpened="cb_DropDownOpened" 
                            KeyUp="cb_KeyUp">

            <telerik:RadComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock TextWrapping="Wrap" Width="{Binding RelativeSource={RelativeSource AncestorType=telerik:RadComboBox},Path=ActualWidth}" Text="{Binding Path=Value}" />
                </DataTemplate>
            </telerik:RadComboBox.ItemTemplate>
        </telerik:RadComboBox>

        <CardControls:ErrorInfo x:Name="errorInfoControl"  Grid.Column="1"  Visibility="Hidden"></CardControls:ErrorInfo>
    </Grid>
</UserControl>

CS:

public partial class SingleDictionaryValueSelector : IMyCustomInterface
{
     ....

    private void cb_KeyDown(object sender, KeyEventArgs e)
    {
        RadComboBox senderCombo = sender as RadComboBox;
        ...

    }

    private void cb_KeyUp(object sender, KeyEventArgs e)
    {
        SearchExecute();
    }





    private void cb_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        RadComboBox senderCombo = sender as RadComboBox;

        ...  
    }

    private void cb_DropDownOpened(object sender, EventArgs e)
    {
       ...
    }

    ...

}
于 2013-06-19T15:02:50.493 に答える