Ala*_*yne 10 data-binding wpf user-controls dependency-properties mvvm
我一直无法找到一个干净,简单的示例,说明如何使用在MVVM框架中具有依赖项属性的WPF 正确实现usercontrol.每当我为usercontrol分配一个datacontext时,我的代码都会失败.
我在尝试着:
我还有很多东西需要学习,并真诚地感谢任何帮助.
这是最顶层的usercontrol中的ItemsControl,它使用依赖项属性TextInControl调用InkStringView用户控件(来自另一个问题的示例).
<ItemsControl
ItemsSource="{Binding Strings}" x:Name="self" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Style TargetType="v:InkStringView">
<Setter Property="FontSize" Value="25"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</DataTemplate.Resources>
<v:InkStringView TextInControl="{Binding text, ElementName=self}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Run Code Online (Sandbox Code Playgroud)
这是带有依赖项属性的InkStringView用户控件.
XAML:
<UserControl x:Class="Nova5.UI.Views.Ink.InkStringView"
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"
x:Name="mainInkStringView"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding TextInControl, ElementName=mainInkStringView}" />
<TextBlock Grid.Row="1" Text="I am row 1" />
</Grid>
Run Code Online (Sandbox Code Playgroud)
Code-Behind file:
namespace Nova5.UI.Views.Ink
{
public partial class InkStringView : UserControl
{
public InkStringView()
{
InitializeComponent();
this.DataContext = new InkStringViewModel(); <--THIS PREVENTS CORRECT BINDING, WHAT
} --ELSE TO DO?????
public String TextInControl
{
get { return (String)GetValue(TextInControlProperty); }
set { SetValue(TextInControlProperty, value); }
}
public static readonly DependencyProperty TextInControlProperty =
DependencyProperty.Register("TextInControl", typeof(String), typeof(InkStringView));
}
Run Code Online (Sandbox Code Playgroud)
}
Rac*_*hel 13
这是你不应该DataContext直接从UserControl自身设置的众多原因之一.
当你这样做时,你就不能再使用任何其他的DataContext了,因为UserControl DataContext被硬编码到只有UserControl有权访问的实例,这种类型会破坏WPF拥有单独的UI和数据层的最大优势之一.
UserControls在WPF中有两种主要的使用方法
独立的UserControl,可以在任何地方使用,无需特定DataContext的要求.
这种类型UserControl通常会暴露DependencyProperties它需要的任何值,并将像这样使用:
<v:InkStringView TextInControl="{Binding SomeValue}" />
Run Code Online (Sandbox Code Playgroud)
我能想到的典型例子是任何通用的例如Calendar控件或Popup控件.
A UserControl表示与特定Model或ViewModel仅使用.
这些UserControls对我来说更常见,而且可能就是你在寻找的东西.我如何使用这样的UserControl的一个例子是:
<v:InkStringView DataContext="{Binding MyInkStringViewModelProperty}" />
Run Code Online (Sandbox Code Playgroud)
或者更频繁地,它将与隐含一起使用DataTemplate.隐式DataTemplate是a DataTemplate和a DataType,否则KeyWPF会在想要呈现指定类型的对象时自动使用此模板.
<Window.Resources>
<DataTemplate DataType="{x:Type m:InkStringViewModel}">
<v:InkStringView />
</DataTemplate>
<Window.Resources>
<!-- Binding to a single ViewModel -->
<ContentPresenter Content="{Binding MyInkStringViewModelProperty}" />
<!-- Binding to a collection of ViewModels -->
<ItemsControl ItemsSource="{Binding MyCollectionOfInkStringViewModels}" />
Run Code Online (Sandbox Code Playgroud)
使用此方法时不需要ContentPresenter.ItemTemplate或ItemsControl.ItemTemplate不需要.
不要混淆这两种方法,它不顺利:)
但无论如何,要更详细地解释您的具体问题
当您像这样创建UserControl时
<v:InkStringView TextInControl="{Binding text}" />
Run Code Online (Sandbox Code Playgroud)
你基本上是在说
var vw = new InkStringView()
vw.TextInControl = vw.DataContext.text;
Run Code Online (Sandbox Code Playgroud)
vw.DataContext 未在XAML中的任何位置指定,因此它从父项继承,从而导致
vw.DataContext = Strings[x];
Run Code Online (Sandbox Code Playgroud)
所以你的绑定设置TextInControl = vw.DataContext.text是有效的,并在运行时解析得很好.
但是,当您在UserControl构造函数中运行它时
this.DataContext = new InkStringViewModel();
Run Code Online (Sandbox Code Playgroud)
将DataContext其设置为值,因此不再自动从父级继承.
所以现在运行的代码如下所示:
var vw = new InkStringView()
vw.DataContext = new InkStringViewModel();
vw.TextInControl = vw.DataContext.text;
Run Code Online (Sandbox Code Playgroud)
当然,InkStringViewModel没有调用的属性text,因此绑定在运行时失败.
小智 5
你快到了。问题是您正在为 UserControl 创建一个 ViewModel。这是一种气味。
从外部看,用户控件的外观和行为应该与任何其他控件一样。您正确地在控件上公开了属性,并将内部控件绑定到这些属性。这都是正确的。
失败的地方是尝试为所有内容创建一个 ViewModel。因此,抛弃那个愚蠢的 InkStringViewModel,让任何使用该控件的人将其视图模型绑定到它。
如果您想问“视图模型中的逻辑怎么样?如果我摆脱它,我将不得不将代码放在代码隐藏中!” 我回答说:“这是业务逻辑吗?无论如何,它都不应该嵌入到您的 UserControl 中。并且 MVVM!= 没有代码隐藏。为您的 UI 逻辑使用代码隐藏。这就是它所属的地方。”
| 归档时间: |
|
| 查看次数: |
6526 次 |
| 最近记录: |