使用MVVM中的依赖属性实现用户控件

4

一个新手问题。在搜索了几个小时后,我仍然无法得到一个关于这种(标准)情况的清晰答案。

我有一个UserControl_1,它将由一个自定义控件和一个WPF控件组成。该用户控件将用于其他WPF用户控件。

最终,我想在主用户控件的XAML中实现这一点:

  XAML
      <i:UserControl_1  TargetDP = "{Binding SourceProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" }" />

源属性绑定到 Main 用户控件的 DataContext,而 TargetDP 是 UserControl_1 中的依赖属性。然后,UserControl_1 将此 TargetDP 传递给其包含的控件。

那么我应该把 DependencyProperty 放在哪里呢?

看起来应该放在代码后面,但我真的很想使用 MVVM 来做这个。

UserControl_1 应该有自己的 ViewModel,与 Main User 控件分开,但信息应该能够通过 UserControl XAML 绑定在主视图模型和用户控件视图模型之间相互传递。

感谢您对此的任何帮助或澄清。(如果出现重复,请原谅,但没有其他文章指定在哪里创建用户控件的新依赖属性或如何实现此操作)。


你的意思是你不知道在 UserControl_1 的 XAML 中放置绑定声明的位置吗? - Clemens
@Clemens 在 UserControl_1 中声明一个新的依赖属性应该放在哪里?比如说,是在 UserControl_1 的视图模型中(如果可能的话),还是在 UserControl_1.XAML.cs(代码后台)中? - Alan Wayne
@Clemens 如果它在代码后台文件中声明,那么如何让依赖属性使用视图模型(或反之亦然)? - Alan Wayne
1
用户控件的依赖属性在用户控件的代码后台中声明,即在这里的UserControl_1.xaml.cs中。然后,您可以像在问题中的示例中那样将此依赖属性绑定到任何视图模型上。用户控件XAML中的控件也可以通过使用相对源绑定和RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = UserControl}来绑定该属性。 - Clemens
@Clemens 我该如何在依赖属性的代码后台中使用,同时为用户控件业务逻辑使用单独的视图模型? - Alan Wayne
1
控件的代码后台包含依赖属性声明。然后将该属性绑定到视图模型属性。属性声明和绑定是独立的事情。我建议获取一本关于WPF中的MVVM的书籍或在线教程。 - Clemens
1个回答

4
这是如何实现的(如果我理解您的意思正确)。您有一个名为MyControl的用户控件。创建MyControlView视图。
<UserControl x:Class="Project.Controls.MyControlView"
             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">
    <Grid HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" 
                   Text="{Binding LabelText}" 
                   VerticalAlignment="Center"
                   HorizontalAlignment="Right"
                   Margin="5,0"/>
        <ComboBox Grid.Row="1" 
                  ItemsSource="{Binding ComboBoxItems}"
                  SelectedItem="{Binding SelectedItem}"
                  HorizontalAlignment="Stretch"
                  Margin="0,0,5,0"/>
    </Grid>
</UserControl>

现在视图模型将是:
public class MyControlViewModel
{
    // Add the public properties for LabelText, ComboBoxItems and SelectedItem
    // and any other logic you require.
}

现在我们来讲解你可能感到困惑的那一点。如果我想在另一个视图中使用这个控件,比如称之为 BigView,我可以这样做:

<Window x:Class="NameSpace.BigView"
        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" 
        xmlns:Controls="clr-namespace:Project.Controls"> // Important reference to your control namespace.
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Controls:MyControlView Grid.Row="0" Margin="0,5" 
                                DataContext="{Binding MyControlA}"/>
        <Controls:MyControlView Grid.Row="1" Margin="0,5" 
                                DataContext="{Binding MyControlB}"/>
    </Grid>
</Window>

现在在视图模型BigViewModel中,您将拥有两个属性。
public RangeSliderControlViewModel MyControlA { get; set; }
public RangeSliderControlViewModel MyControlB { get; set; }

那么你可以通过 MyControlA.LabelText = "一些文本" 等方式访问每个控件的属性。请注意,在 BigViewModel 中,MyControlA/MyControlB 不需要实现 INotifyPropertyChanged,但是您控件中的属性必须这样做,以便更新能够向上传递并更新 BigView

希望这有所帮助。


@Kilercam 目标依赖属性可以放在MyControlView的"DataContext"中吗?谢谢。 - Alan Wayne
@Kilercam 看起来在上面的代码中,BigViewModel正在设置用户控件的DataContext,但这不需要BigViewModel对用户控件有深入的了解吗?这是我想避免的。谢谢。 - Alan Wayne
2
嗨,我不确定你所说的“亲密知识”是什么意思。 BigViewmodel 需要的只是对包含用户控件的命名空间的引用。就这样。它不需要处理任何逻辑,因为这是委托给底层控件视图模型的。对于依赖属性,您可以将其放在代码后面以进行此类操作 - 有些 MVVM 纯粹主义者会对此感到疯狂(我曾经是其中之一!),但是一旦您获得更多经验,您就会意识到在某些情况下没有必要反对该模式。其他选项... - MoonKnight
创建依赖属性的最初步骤是先创建用户控件,然后从该控件继承并添加你需要的依赖属性 - 尽管这种方法不太干净。另一个选项是使用 System.Windows.Interactivity.Behavior 来为你的控件添加可绑定属性。我认为在这里,代码后台是可以的。 - MoonKnight
1
不,完全不需要,在ViewModel中放置其余的逻辑。只是对于DP,您需要直接引用视图。对于其他任何事情,请放在ViewModel中。请注意,如果您不想在代码后面使用DP,则还有其他选项-总是有其他选项。 - MoonKnight
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接