WPF 用户控件:我可以绑定来自内部和外部数据上下文的属性吗?
WPF User control: can I bind properties from an internal and an external datacontext?
我正在尝试在 WPF/XAML 中构建我自己的日历控件,既可以作为练习,也可以用于业余项目。这个日历将是一个网格,其中每个单元格显然代表所选月份中的一天。每个单元格都应该能够显示项目列表。日历的输入应该是月份的标识和日期列表。那些 "days" 将是自定义类型,例如
public class CalendarDay
{
public int DayNumber {get; set;}
public List<DayItem> Items {get; set;}
}
其中 DayItem
可以代表约会或待办事项。
我将其实现为用户控件。此日历的 XAML 是一个 ControlTemplate
,其中包含 1x7 的 UniformGrid
日期名称(数据绑定到集合 7 字符串)和 6x7 的 UniformGrid
天(数据绑定到 CalendarDay
的集合)。
包含此日历的视图(用户控件)在概念上如下所示:
<UserControl name="myView" ... xmlns:cal="clr-namespace:the calendar namespace">
<Grid>
<cal:Calendar Days="{Binding DaysWithItems}" CurrentMonth="{Binding DisplayMonth}" />
</Grid>
</UserControl>
当我应用 MVVM 时,myView
将有一个 DataContext 设置为某个视图模型 class,它有一个 属性 DaysWithItems
(列表CalenderDay
个实例)和一个 属性 DisplayMonth
.
理想情况下,此日历控件的使用者只需提供上述两个输入。此外,从 myView
的角度来看(双关语是巧合),DaysWithItems
应该是一个包含 28、29、30 或 31 个元素的列表,具体取决于月份。这意味着列表应该以某种方式填充到 42 个项目。我认为这应该是日历控件的责任,而不是 myView
的视图模型。
请注意,我也没有提供日期名称。这也应该是日历控件的责任。这不应明确提供。
这是我的问题。如果在日历的控件模板中,我想绑定日期名称的字符串集合和 CalendarDay
的 42 元素集合,数据上下文应该是 Calendar
class 本身(因为我之前解释过的责任)。
另一方面,在 myView
中,我将日历绑定到 myView
的 DaysWithItems
(包含 28..31 个元素的(逻辑)集合),所以日历的datacontext 应该是 myView
的视图模型。
我可以使用某种内部数据上下文(= "internal" 到控件模板)和某种外部数据上下文(= 日历控件使用者提供的数据上下文)吗?
绑定到 DataContext 以外的东西的最简单方法是使用 ElementName
您可以执行以下操作:
UserControl.xaml.cs 示例:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(UserControl1), new PropertyMetadata(0));
}
UserControl.Xaml
<UserControl x:Class="GridSplitterTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" x:Name="MyControl"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Content="{Binding ElementName=MyControl, Path=MyProperty}"></Button>
</Grid>
</UserControl>
通过使用 ElementName 并指向 UserControl,您将绕过 DataContext 并能够绑定到 UC 内的属性。
下面是这类数据绑定的要点。当您想要从设置为 DataContext
的对象绑定到 属性 时,您可以使用正常的 Binding Path
:
<TextBlock Text="{Binding PropertyOfDataContextObject}" />
但是,当您还想将数据绑定到 属性(从在 UserControl
(或 Window
)中声明的 UserControl
内部)时,您应该使用 RelativeSource Binding
:
<TextBlock Text="{Binding PropertyOfUserControl, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:YourUserControl}}}" />
您也可以命名一个控件并使用 Binding.ElementName
Property 来引用它:
<TextBlock Text="{Binding PropertyOfNamedControl, ElementName=NameOfControl}" />
我正在尝试在 WPF/XAML 中构建我自己的日历控件,既可以作为练习,也可以用于业余项目。这个日历将是一个网格,其中每个单元格显然代表所选月份中的一天。每个单元格都应该能够显示项目列表。日历的输入应该是月份的标识和日期列表。那些 "days" 将是自定义类型,例如
public class CalendarDay
{
public int DayNumber {get; set;}
public List<DayItem> Items {get; set;}
}
其中 DayItem
可以代表约会或待办事项。
我将其实现为用户控件。此日历的 XAML 是一个 ControlTemplate
,其中包含 1x7 的 UniformGrid
日期名称(数据绑定到集合 7 字符串)和 6x7 的 UniformGrid
天(数据绑定到 CalendarDay
的集合)。
包含此日历的视图(用户控件)在概念上如下所示:
<UserControl name="myView" ... xmlns:cal="clr-namespace:the calendar namespace">
<Grid>
<cal:Calendar Days="{Binding DaysWithItems}" CurrentMonth="{Binding DisplayMonth}" />
</Grid>
</UserControl>
当我应用 MVVM 时,myView
将有一个 DataContext 设置为某个视图模型 class,它有一个 属性 DaysWithItems
(列表CalenderDay
个实例)和一个 属性 DisplayMonth
.
理想情况下,此日历控件的使用者只需提供上述两个输入。此外,从 myView
的角度来看(双关语是巧合),DaysWithItems
应该是一个包含 28、29、30 或 31 个元素的列表,具体取决于月份。这意味着列表应该以某种方式填充到 42 个项目。我认为这应该是日历控件的责任,而不是 myView
的视图模型。
请注意,我也没有提供日期名称。这也应该是日历控件的责任。这不应明确提供。
这是我的问题。如果在日历的控件模板中,我想绑定日期名称的字符串集合和 CalendarDay
的 42 元素集合,数据上下文应该是 Calendar
class 本身(因为我之前解释过的责任)。
另一方面,在 myView
中,我将日历绑定到 myView
的 DaysWithItems
(包含 28..31 个元素的(逻辑)集合),所以日历的datacontext 应该是 myView
的视图模型。
我可以使用某种内部数据上下文(= "internal" 到控件模板)和某种外部数据上下文(= 日历控件使用者提供的数据上下文)吗?
绑定到 DataContext 以外的东西的最简单方法是使用 ElementName
您可以执行以下操作:
UserControl.xaml.cs 示例:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(UserControl1), new PropertyMetadata(0));
}
UserControl.Xaml
<UserControl x:Class="GridSplitterTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" x:Name="MyControl"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Button Content="{Binding ElementName=MyControl, Path=MyProperty}"></Button>
</Grid>
</UserControl>
通过使用 ElementName 并指向 UserControl,您将绕过 DataContext 并能够绑定到 UC 内的属性。
下面是这类数据绑定的要点。当您想要从设置为 DataContext
的对象绑定到 属性 时,您可以使用正常的 Binding Path
:
<TextBlock Text="{Binding PropertyOfDataContextObject}" />
但是,当您还想将数据绑定到 属性(从在 UserControl
(或 Window
)中声明的 UserControl
内部)时,您应该使用 RelativeSource Binding
:
<TextBlock Text="{Binding PropertyOfUserControl, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:YourUserControl}}}" />
您也可以命名一个控件并使用 Binding.ElementName
Property 来引用它:
<TextBlock Text="{Binding PropertyOfNamedControl, ElementName=NameOfControl}" />