XAML UserControl继承

Ste*_*TNT 24 c# wpf inheritance xaml windows-phone-8

来自Java,我真的习惯于制作GUI组件的常用做法:我通常会做一些基类,它包含GUI组件的所有常用对象,然后我扩展它.

所以,基本上,这是我想用C#和XAML实现的.

为了使问题清楚,这是我正在做的一个例子(那是行不通的!):

我们有一个拥有自己的XAML的基类

<UserControl x:Class="BaseClass"
    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"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
        <Border BorderBrush="Aqua" BorderThickness="10" CornerRadius="10" x:Name="Border" HorizontalAlignment="Left" Height="480" VerticalAlignment="Top" Width="480"/>

    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

然后我们有一个扩展第一个类的类

<base:BaseClass x:Class="DerivedClass"
    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:base="clr-namespace:BaseClass"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="60" d:DesignWidth="200">

    <Grid x:Name="LayoutRoot" Margin="0" Width="200" Height="60" MaxWidth="200" MaxHeight="60" Background="{StaticResource PhoneAccentBrush}">        
        <TextBlock x:Name="dummyText" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Dummy Plugin" VerticalAlignment="Top" Height="40" Width="180" Foreground="White" TextAlignment="Center"/>
    </Grid>
</base:BaseClass>
Run Code Online (Sandbox Code Playgroud)

从2个XAML代码开始,我想要做的就是DerivedClass进入BaseClass容器.这将允许我在各种派生类之间共享组件,而不必在每次需要时编写代码.

例如,如果我希望我的所有组件都有这个圆形边框,我想把它放在bass类中,然后将它放在所有派生类中,而不必重写它.

当然,每个C#类有它自己的InitializeComponent()方法和这可能意味着所导出的组件将通过除去基类的一个建立其自己的内容.

DerivedClass构造函数中删除方法即使在派生类中也提供了基本内容,但是,当然,我丢失了我在XAML设计窗口中所做的一切DerivedClass.

从中调用基础构造函数DerivedClass没有效果,因为它在派生之前调用InitializeComponent().

所以问题是:如何在不破坏派生类的XAML设计的情况下,将基类的XAML设计用于派生类?有没有办法简单地将内容添加到基类,同时仍然使用设计器本身?

(我知道我可以删除派生类的XAML并通过代码执行我想要做的事情,但我想知道我是否可以只使用设计器来执行此操作,因为我不想编写GUI时设计师可用)

编辑:

在HighCore的回复之后,我做了一些适用于Windows Phone但我不确定我做的是正确的事情(是的,它有效,但可能是错的!).

这是我做的:

BaseControl.xaml

<UserControl x:Class="TestInheritance.BaseControl"
    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"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">


     <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">        
        <TextBlock HorizontalAlignment="Center">BASE</TextBlock>        
        <ContentPresenter Name="Presenter" Content="{Binding PresenterContent}"/>
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

BaseControl.xaml.cs

namespace TestInheritance
{
    public partial class BaseControl : UserControl
    {

        public Grid PresenterContent { get; set; }        

        public BaseControl()
        {
            DataContext = this;
            InitializeComponent();            
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

DerivedControl.xaml

<local:BaseControl x:Class="TestInheritance.DerivedControl"
    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:TestInheritance"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <local:BaseControl.PresenterContent>
        <Grid>
            <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center">DERIVED</TextBlock>
        </Grid>
    </local:BaseControl.PresenterContent>
</local:BaseControl>
Run Code Online (Sandbox Code Playgroud)

请注意,DerivedClass是一个实例BaseClass,因为我需要他们有其他原因一些常见的属性/方法.

您对我的解决方案有何看法?是否有意义?

Fed*_*gui 64

好吧,让我把它分成几部分:

来自Java

忘了java.这是一种非常陈旧的语言,自90年代以来就没有发展过.C#是一百万倍,WPF是迄今为止最好的UI框架.

从我所看到的,诸如swing之类的java UI框架在概念上类似于.Net的winforms,它也被WPF取代.

WPF(以及它基于XAML的兄弟)与其他任何框架都有着根本的不同,因为它们通过样式和模板增强了自定义功能,并支持DataBinding.

因此,在WPF上启动时需要重要的Mindshift.


我通常做一些基类,它包含我的GUI组件的所有常见对象,然后我扩展它.

在WPF中,有一个内容模型,通过引入"任何内容"的功能,消除了对继承和其他膨胀的不必要实践的需要.

例如,a Button可以这样定义:

<Button>
    <Button.Content>
        <StackPanel Orientation="Horizontal">
            <Ellipse Fill="Red" Height="10" Width="10" Margin="2"/>
            <TextBlock Text="Click Me"/>
        </StackPanel>
    <Button.Content>
 </Button>
Run Code Online (Sandbox Code Playgroud)

结果

带红点的按钮

只需定义它的内容就不需要继承Button.

WPF提供了一个额外的优点,非常方便,ContentProperty属性定义了XAML标记的内容<Button> </Button>.Button派生自ContentControl,声明如下:

//Declaration of the System.Windows.Control.ContentControl class,
//inside the PresentationFramework.dll assembly
//...  
[ContentProperty("Content")]
public class ContentControl: Control //...
{
   //...
}
Run Code Online (Sandbox Code Playgroud)

这意味着以下XAML在功能上与上述相同:

<Button>
   <StackPanel Orientation="Horizontal">
       <Ellipse Fill="Red" Height="10" Width="10" Margin="2"/>
       <TextBlock Text="Click Me"/>
    </StackPanel>
</Button>
Run Code Online (Sandbox Code Playgroud)
  • 请注意,我们已删除了<Button.Content>标记,因为该ContentProperty属性会处理该标记.

所有这一切都归功于一个名为ControlTemplates的功能,该功能定义了Control的视觉外观,与其行为无关.


我想做的是将DerivedClass放入BaseClass容器中.

有几种方法可以实现这一点,其中一种方法是利用ControlTemplates和定义XAML中将承载内容的特定容器:

<UserControl x:Class="BaseClass">
    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <DockPanel>
                <TextBlock DockPanel.Dock="Top" Text="I'm the Container"/>

                <!-- This is where the Hosted Content will be placed -->
                <ContentPresenter ContentSource="Content"/>
            </DockPanel>
        </ControlTemplate>
     </UserControl.Template>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样重用这个模板:

<Window>
   <my:BaseClass>
       <Border Background="Gray" BorderBrush="Blue" BorderThickness="2"
               VerticalAlignment="Center" HorizontalAlignment="Center">
           <TextBlock Text="Im the Hosted Content" Foreground="AliceBlue"/>
       </Border>
   </my:BaseClass>
</Window>
Run Code Online (Sandbox Code Playgroud)

这导致:

应用程序窗口

不需要继承或任何程序代码.


在WPF中启动的另一个非常重要的方面,在上面的"重大Mindshift"链接中进行了广泛的解释,我在这里告诉大家:

在WPF中编写单行代码之前,先学习MVVM

  • 大多数情况下,您不在WPF UI元素中放置任何代码,因为大多数事情都可以通过DataBinding(在上面的"DataBinding"链接中介绍)或通过实现可重用 附加行为附加属性来实现.只有特定VIEW的代码才能放在代码后面,而不涉及数据或业务逻辑

  • 您可能习惯在其他框架中使用的样板,例如:

    txtLastName.Text = person.LastName;
    txtFirstName.Text = person.FirstName;
    btnSubmit.IsEnabled = person.IsActive;
    
    Run Code Online (Sandbox Code Playgroud)

    因为DataBinding,在WPF中完全不需要这样的东西.


另一个在UI中显示数据时具有高度灵活性的概念是WPF DataTemplates,它允许您定义在屏幕上"呈现"某些数据类型时要使用的特定UI.


由于上述所有原因,WPF与大多数UI框架根本不同,因此不再需要在其他框架中常见的所有可怕的样板和黑客,

我建议您阅读所有提供的链接,并在定义应用程序的结构和UI时记住所有这些概念和实践.

如果您需要进一步的帮助,请告诉我.

  • 这个句子的+1"忘了java.这是一个非常陈旧的语言,自90年代以来就没有进化过" (18认同)
  • 真?这就是为什么存在20多个不同的MVVM第三方(大多数开源)库,它们有助于实现这个混乱,因为它实现起来很简单,并且比现有的其他任何东西都好得多?我建议你以更诚实的方式展示你的专业知识.您只是将http://stackoverflow.com/questions/27625181/mvvm-confused-about-viewmodellocator-and-datatemplate-leading-to-viewfirst-vs中的一些有效问题和问题放在一边,批评与主题无关正在讨论中.你最后的陈述必须是一个笑话(我希望).说够了. (3认同)
  • @StepTNT在WPF,Silverlight,WinRT和Windows Phone之间的XAML实现上略有不同,但更高级别的概念(Styles,ControlTemplates,DataTemplates,Content Model,MVVM,DataBinding)都是一样的. (2认同)
  • 市面上有几十种语言和工具,有些是根据工作来选择的,有些是因为部署要求而选择的,还有一些是因为客户或工作公司施加的限制而选择的。有时这只是个人品味的问题。我并不认为 Java 较差,只是考虑到过去它的“所有权”问题,它还没有赶上 .NET 的所有优点。 (2认同)
  • 您关于 Java 与 WPF 的说法大多只是意见,基于事实的说法(Java 自 90 年代以来没有发展)完全不真实。我本人不是 Java 的粉丝,但您的开场白是题外话,删除它会改善答案。 (2认同)