自定义我的控件的一部分
Customize parts of my control
我正在开发通用 window SDK。
SDK 的主要入口点是派生的 UserControl class,它公开了一些功能。
我们不允许用户完全改变外观,这就是我不喜欢 CustomControl + generic.xaml + 模板部件方法的原因。
但是,我们希望允许自定义一些子项。就像我们控制的三个不同按钮一样。我想提供合理的默认值 styles/templates/content,但我希望我的用户能够完全重新设计这些子项,以备不时之需。或者,只是改变例如背景颜色,如果他们想这样做的话。
最好的方法是什么?
- 公开我的控件的(依赖项?)属性
Style Button1Style
?
- 公开我的控件的(依赖项?)属性
ControlTemplate Button1Template
?
- 公开我的控件的(依赖项?)属性
DataTemplate Button1ContentTemplate
?
- 这些的组合?
- 其他方式?
SDK 是可移植的,需要支持 Windows 8.1 和 10,Store 和 Phones。
更新:我知道数据绑定工作需要依赖属性。我不知道我的用户是否会使用数据绑定,或者他们不会。
我不需要动画。
我期望的用例如下:
- 大多数客户应该对默认外观感到满意 - 对于他们,我只需要提供合理的默认外观。
- 有些人会想要更改某些子控件的颜色或边距。
- 有些人会用他们自定义的图标替换我们的图标。
- 有些将完全修改我们按钮的样式和模板。
我想让他们在 MS Blend 中进行 2-4 次,仅在 XAML 中进行。怎么样?
@Soonts,这里有很多变数。而且,尽管许多 Whosebug 书呆子对开发人员在一个问题中提出多个问题感到非常生气,但我认为我们可以共同努力以获得您的答案。
首先,我认为你应该回顾一下我关于这个主题的文章。它侧重于用户控件中的双向绑定,诚然,这是一个技巧。
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 标记了您的问题,所以利用 属性 元数据中定义的已更改事件很重要。同样,这在文章中。
最后,我写了一个重要的用户控件派生控件,所以我可以确认你想要完成的事情是肯定有可能的。如果你想查看我的代码,看看我们是否在做你想窃取的任何东西,你也可以这样做。
祝你好运。
已实施 #1,工作正常。
- Style/template那些部分,把那些styles/templates放在单独的资源字典里"DefaultStyles".
- 创建 code behind for that resource dictionary。这样做是为了避免疯狂的 "ms-appx:///" URI,而是通过 class 名称引用字典。
- 在用户控件代码中,为我的控件的可自定义部分添加几个 "Style" 类型的依赖属性。
- 在用户控件代码中,在构造函数中,将控件的根元素(但不是控件本身)的数据上下文设置为
this
。
在用户控件 XAML 中,包括 DefaultStyles 资源:
<ResourceDictionary.MergedDictionaries>
<local:DefaultStyles />
</ResourceDictionary.MergedDictionaries>
在用户控件 XAML 中,引用样式:<Button Style="{Binding MyButtonStyle, TargetNullValue={StaticResource MyButtonDefaultStyle}}" />
其中 MyButtonStyle
是在步骤 #3 中创建的依赖项 属性,MyButtonDefaultStyle
是在步骤 #1
中创建的默认样式
在客户端应用页面中:
<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>
最后,在客户端应用页面:
<sdk:TheControl MyButtonStyle={StaticResource sss} />
这样,一切都开箱即用,我的用户无需复制粘贴 XAML 页面即可调整单个边距或颜色,或者完全忽略我提供的 styles/templates并创建自己的。
请问有没有更简单的方法?
任务 "Allow user to override styles, partially or completely" 听起来并不难完成。
更新: 由于某些原因,在 windows phone 8.1 中,您无法设置 Content
属性样式(没有错误,只是没有效果)。幸运的是,您可以改为设置 ContentTemplate
属性,这似乎适用于所有平台。
啊,你的问题改了。给你。
这是我过去的做法。
<UserControl>
<Grid Background="{x:Bind MyBackground, FallbackValue=White}">
<TextBlock Text="{x:Bind MyText, FallbackValue=DesigntimeValue }" />
</Grid>
</UserControl>
Please note that {x:Bind} does not support designtime values, so using FallBackValue is basically giving you the designetime value. Don't confuse this with your default value.
那么这个代码隐藏:
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
}
This is just how we implement INotifyPropertyChanged
in Template 10 (http://aka.ms/template10). You can implement it however you like.
并像这样使用它:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:MyUserControl MyBackground="Yellow" MyText="JerryNixon" />
</Grid>
The default values is what you will see in the designtime of your app, not the fallback. FallBackValues will be what you see when designing the user control itself.
值得指出的是,您可以将这些属性中的任何一个替换为依赖属性。您想要这样做的唯一原因是您希望它们具有动画效果。
希望对您有所帮助。祝你好运。
我正在开发通用 window SDK。
SDK 的主要入口点是派生的 UserControl class,它公开了一些功能。
我们不允许用户完全改变外观,这就是我不喜欢 CustomControl + generic.xaml + 模板部件方法的原因。
但是,我们希望允许自定义一些子项。就像我们控制的三个不同按钮一样。我想提供合理的默认值 styles/templates/content,但我希望我的用户能够完全重新设计这些子项,以备不时之需。或者,只是改变例如背景颜色,如果他们想这样做的话。
最好的方法是什么?
- 公开我的控件的(依赖项?)属性
Style Button1Style
? - 公开我的控件的(依赖项?)属性
ControlTemplate Button1Template
? - 公开我的控件的(依赖项?)属性
DataTemplate Button1ContentTemplate
? - 这些的组合?
- 其他方式?
SDK 是可移植的,需要支持 Windows 8.1 和 10,Store 和 Phones。
更新:我知道数据绑定工作需要依赖属性。我不知道我的用户是否会使用数据绑定,或者他们不会。 我不需要动画。
我期望的用例如下:
- 大多数客户应该对默认外观感到满意 - 对于他们,我只需要提供合理的默认外观。
- 有些人会想要更改某些子控件的颜色或边距。
- 有些人会用他们自定义的图标替换我们的图标。
- 有些将完全修改我们按钮的样式和模板。
我想让他们在 MS Blend 中进行 2-4 次,仅在 XAML 中进行。怎么样?
@Soonts,这里有很多变数。而且,尽管许多 Whosebug 书呆子对开发人员在一个问题中提出多个问题感到非常生气,但我认为我们可以共同努力以获得您的答案。
首先,我认为你应该回顾一下我关于这个主题的文章。它侧重于用户控件中的双向绑定,诚然,这是一个技巧。
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 标记了您的问题,所以利用 属性 元数据中定义的已更改事件很重要。同样,这在文章中。
最后,我写了一个重要的用户控件派生控件,所以我可以确认你想要完成的事情是肯定有可能的。如果你想查看我的代码,看看我们是否在做你想窃取的任何东西,你也可以这样做。
祝你好运。
已实施 #1,工作正常。
- Style/template那些部分,把那些styles/templates放在单独的资源字典里"DefaultStyles".
- 创建 code behind for that resource dictionary。这样做是为了避免疯狂的 "ms-appx:///" URI,而是通过 class 名称引用字典。
- 在用户控件代码中,为我的控件的可自定义部分添加几个 "Style" 类型的依赖属性。
- 在用户控件代码中,在构造函数中,将控件的根元素(但不是控件本身)的数据上下文设置为
this
。 在用户控件 XAML 中,包括 DefaultStyles 资源:
<ResourceDictionary.MergedDictionaries> <local:DefaultStyles /> </ResourceDictionary.MergedDictionaries>
在用户控件 XAML 中,引用样式:
<Button Style="{Binding MyButtonStyle, TargetNullValue={StaticResource MyButtonDefaultStyle}}" />
其中MyButtonStyle
是在步骤 #3 中创建的依赖项 属性,MyButtonDefaultStyle
是在步骤 #1 中创建的默认样式
在客户端应用页面中:
<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>
最后,在客户端应用页面:
<sdk:TheControl MyButtonStyle={StaticResource sss} />
这样,一切都开箱即用,我的用户无需复制粘贴 XAML 页面即可调整单个边距或颜色,或者完全忽略我提供的 styles/templates并创建自己的。
请问有没有更简单的方法?
任务 "Allow user to override styles, partially or completely" 听起来并不难完成。
更新: 由于某些原因,在 windows phone 8.1 中,您无法设置 Content
属性样式(没有错误,只是没有效果)。幸运的是,您可以改为设置 ContentTemplate
属性,这似乎适用于所有平台。
啊,你的问题改了。给你。
这是我过去的做法。
<UserControl>
<Grid Background="{x:Bind MyBackground, FallbackValue=White}">
<TextBlock Text="{x:Bind MyText, FallbackValue=DesigntimeValue }" />
</Grid>
</UserControl>
Please note that {x:Bind} does not support designtime values, so using FallBackValue is basically giving you the designetime value. Don't confuse this with your default value.
那么这个代码隐藏:
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
}
This is just how we implement
INotifyPropertyChanged
in Template 10 (http://aka.ms/template10). You can implement it however you like.
并像这样使用它:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:MyUserControl MyBackground="Yellow" MyText="JerryNixon" />
</Grid>
The default values is what you will see in the designtime of your app, not the fallback. FallBackValues will be what you see when designing the user control itself.
值得指出的是,您可以将这些属性中的任何一个替换为依赖属性。您想要这样做的唯一原因是您希望它们具有动画效果。
希望对您有所帮助。祝你好运。