自定义我的控件的一部分

时间:2016-02-02 16:45:16

标签: windows-phone-8.1 windows-store-apps winrt-xaml win-universal-app

我正在开发一个通用窗口SDK。

SDK的主要入口点是一个UserControl派生类,它公开了一些功能。

我们不允许我们的用户完全改变外观,这就是我不喜欢CustomControl + generic.xaml +模板部件方法的原因。

但是,我们希望自定义一些子项。就像我们控制的三个不同按钮一样。我想提供合理的默认样式/模板/内容,但我希望我的用户能够完全重新设计这些子项,以防他们想要。或者,只需更改,例如背景颜色,如果他们想这样做。

最好的方法是什么?

  1. 我的控件Style Button1Style的曝光(依赖?)属性?
  2. 我的控件ControlTemplate Button1Template的曝光(依赖?)属性?
  3. 我的控件DataTemplate Button1ContentTemplate的曝光(依赖?)属性?
  4. 这些的组合?
  5. 其他一些方式?
  6. SDK是可移植的,需要支持Windows 8.1和10,Store和Phones。

    更新:我知道数据绑定工作需要依赖项属性。我不知道我的用户是使用数据绑定还是他们不会。 我不需要动画。

    我期待的用例如下:

    1. 大多数客户应该对默认外观感到满意 - 对于他们我只需要提供合理的默认外观。
    2. 有些人希望更改某些子控件的颜色或边距。
    3. 有些人会用自定义图标替换我们的图标。
    4. 有些人会完全修改按钮的样式和模板。
    5. 我想让他们在MS Blend中做2-4,只在XAML中。怎么样?

3 个答案:

答案 0 :(得分:0)

@Soonts,这里有很多变数。而且,虽然许多StackOverflow书呆子在一个问题中对开发人员提出多个问题的努力得到了解决,但我认为我们可以共同努力以获得答案。

首先,我认为你应该回顾一下我关于这个主题的文章。它着重于用户控件中的双向绑定,这无疑是一种技巧。

  

http://blog.jerrynixon.com/2013/07/solved-two-way-binding-inside-user.html

其次,我认为理解ControlTemplate绑定,属性动画和绑定以及DataTemplate范围很重要。我在@ Microsoft Virtual Academy的课程中非常深入地讨论了这个主题。

  

https://mva.microsoft.com/en-us/training-courses/xaml-for-windows-10-controls-14482

对大多数问题的简短回答是依赖属性是您所需要的。由于您使用Windows 8标记了问题,因此利用属性元数据中定义的已更改事件非常重要。同样,这是在文章中。

最后,我写了一个来自用户控制的重要控件,所以我可以确认你想要完成的事情当然是可能的。如果你想查看我的代码,看看我们是否正在做你想要窃取的任何事情,你也可以这样做。

  

https://github.com/Windows-XAML/Template10/blob/master/Template10%20(Library)/Controls/HamburgerMenu.xaml.cs

祝你好运。

答案 1 :(得分:0)

实施#1,效果更好。

  1. 样式/模板这些部分,将这些样式/模板放在单独的资源字典中" DefaultStyles"。
  2. 创建code behind for that resource dictionary。这样做是为了避免这种疯狂的" ms-appx:///" URI,而是按类名引用字典。
  3. 在用户控制代码中,添加类型"样式"的几个依赖项属性。用于我可控制的可自定义部分。
  4. 在用户控制代码中,在构造函数中,将控件的根元素(但不是控件本身)的数据上下文设置为this
  5. 在用户控件XAML中,包含DefaultStyles资源:

    <ResourceDictionary.MergedDictionaries>
        <local:DefaultStyles />
    </ResourceDictionary.MergedDictionaries>
    
  6. 在用户控件XAML中,引用样式:<Button Style="{Binding MyButtonStyle, TargetNullValue={StaticResource MyButtonDefaultStyle}}" />其中MyButtonStyle是在步骤#3中创建的依赖项属性,MyButtonDefaultStyle是在步骤#1中创建的默认样式

  7. 在客户端应用的页面中:

    <ResourceDictionary.MergedDictionaries>
        <sdk:DefaultStyles />
    </ResourceDictionary.MergedDictionaries>
    <!-- Debug code: override a single property -->
    <Style x:Key="sss" TargetType="Button" BasedOn="{StaticResource MyButtonDefaultStyle}">
        <Setter Property="Foreground" Value="Green" />
    </Style>
    
  8. 最后,在客户端应用的页面中:

    <sdk:TheControl MyButtonStyle={StaticResource sss} />
    
  9. 这样,一切都开箱即用,我的用户可以调整单个边距或颜色而无需复制粘贴XAML页面,或者完全忽略我提供的样式/模板并创建自己的样式/模板。

    我想知道有更简单的方法吗?

    任务&#34;允许用户部分或全部覆盖样式&#34;并不听起来应该很难完成。

    更新:出于某种原因,在Windows Phone 8.1上,您无法设置Content属性(没有错误,只是没有效果)。幸运的是,您可以设置ContentTemplate属性,这似乎适用于所有平台。

答案 2 :(得分:0)

啊,你改变了你的问题。你走了。

以下是我过去的做法。

<UserControl>
    <Grid Background="{x:Bind MyBackground, FallbackValue=White}">
        <TextBlock Text="{x:Bind MyText, FallbackValue=DesigntimeValue }" />
    </Grid>
</UserControl>
  

请注意{x:Bind}不支持设计时值,因此使用FallBackValue基本上会为您提供设计时值。不要将此与您的默认值混淆。

然后这个代码隐藏:

public sealed partial class MyUserControl : UserControl, INotifyPropertyChanged
{
    public MyUserControl()
    {
        InitializeComponent();
    }

    Brush _MyBackground = new SolidColorBrush(Colors.Blue);
    public Brush MyBackground { get { return _MyBackground; } set { Set(ref _MyBackground, value); } }

    string _MyText = "Default value";
    public string MyText { get { return _MyText; } set { Set(ref _MyText, value); } }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (!Equals(storage, value))
        {
            storage = value;
            RaisePropertyChanged(propertyName);
        }
    }

    void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    #endregion  
}
  

这就是我们在模板10(http://aka.ms/template10)中实施INotifyPropertyChanged的方式。你可以随意实现它。

并像这样使用它:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <local:MyUserControl MyBackground="Yellow" MyText="JerryNixon" />
</Grid>
  

您将在应用的设计时间看到默认值,而不是后备。 FallBackValues将是您在设计用户控件时所看到的。

值得指出的是,您可以使用依赖项属性替换任何这些属性。您想要这样做的唯一原因是,如果您打算将它们设置为动画。

我希望这会有所帮助。祝你好运。