C# 如何为WPF中具有视图模型的用户控件设置参数

C# 如何为WPF中具有视图模型的用户控件设置参数,c#,wpf,xaml,C#,Wpf,Xaml,在WPF中,我有一个包含用户控件的窗口。窗口和用户控件都有一个视图模型。我想将一个参数从窗口的VM传递到UC的VM。我看了很多遍之后,还没找到办法 窗口XAML将其数据上下文设置为其VM。UC包含参数的自定义依赖项属性。我想使用SetBinding将DP绑定到UC VM 如果我将UC数据上下文设置为其VM,则参数绑定不起作用。如果我没有设置UC数据上下文,那么参数绑定可以工作,但是UC VM没有被引用 如何传递参数并绑定到UC VM UC XAML <UserControl x:Name=

在WPF中,我有一个包含用户控件的窗口。窗口和用户控件都有一个视图模型。我想将一个参数从窗口的VM传递到UC的VM。我看了很多遍之后,还没找到办法

窗口XAML将其数据上下文设置为其VM。UC包含参数的自定义依赖项属性。我想使用
SetBinding
将DP绑定到UC VM

如果我将UC数据上下文设置为其VM,则参数绑定不起作用。如果我没有设置UC数据上下文,那么参数绑定可以工作,但是UC VM没有被引用

如何传递参数并绑定到UC VM

UC XAML

<UserControl x:Name="userControl" x:Class="Test_Paramaterized_UserControl_with_MVVM.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" 
             xmlns:local="clr-namespace:Test_Paramaterized_UserControl_with_MVVM"
             xmlns:view="clr-namespace:Daavlin.SmartTouch.STUV_WPF.View"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
      <Grid Margin="10">
        <Border BorderThickness="3" BorderBrush="Black" Padding="10">
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="UserControl1 View: "/>
                    <TextBlock Text="{Binding ElementName=userControl, Path=PropUserControlView, Mode=OneWay}" FontWeight="Bold"/>
                </StackPanel>
                <Rectangle Height="5"/>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="UserControl1 ViewModel: " />
                    <TextBlock Text="{Binding PropUserControlViewModel, FallbackValue=propUserControlViewModel 2}" FontWeight="Bold">
                        <TextBlock.DataContext>
                            <local:UserControl1ViewModel/>
                        </TextBlock.DataContext>
                    </TextBlock>
                </StackPanel>
            </StackPanel>
        </Border>
    </Grid>
</UserControl>
<Window x:Class="Test_Paramaterized_UserControl_with_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Test_Paramaterized_UserControl_with_MVVM"
        Title="MainWindow" >
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid VerticalAlignment="Top" >
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="20">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="MainWindow1 ViewModel: "/>
                <TextBox Text="{Binding PropWindowViewModel, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold"/>
            </StackPanel>
            <Rectangle Height="10"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="UserControl1 (fixed value Fixed): " VerticalAlignment="Center"/>
                <local:UserControl1 PropUserControlView="Fixed"/>
            </StackPanel>
            <Rectangle Height="10"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="UserControl1 (bound to MainWindows VM): " VerticalAlignment="Center"/>
                <local:UserControl1 PropUserControlView="{Binding PropWindowViewModel}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>
窗口XAML

<UserControl x:Name="userControl" x:Class="Test_Paramaterized_UserControl_with_MVVM.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" 
             xmlns:local="clr-namespace:Test_Paramaterized_UserControl_with_MVVM"
             xmlns:view="clr-namespace:Daavlin.SmartTouch.STUV_WPF.View"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
      <Grid Margin="10">
        <Border BorderThickness="3" BorderBrush="Black" Padding="10">
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="UserControl1 View: "/>
                    <TextBlock Text="{Binding ElementName=userControl, Path=PropUserControlView, Mode=OneWay}" FontWeight="Bold"/>
                </StackPanel>
                <Rectangle Height="5"/>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="UserControl1 ViewModel: " />
                    <TextBlock Text="{Binding PropUserControlViewModel, FallbackValue=propUserControlViewModel 2}" FontWeight="Bold">
                        <TextBlock.DataContext>
                            <local:UserControl1ViewModel/>
                        </TextBlock.DataContext>
                    </TextBlock>
                </StackPanel>
            </StackPanel>
        </Border>
    </Grid>
</UserControl>
<Window x:Class="Test_Paramaterized_UserControl_with_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Test_Paramaterized_UserControl_with_MVVM"
        Title="MainWindow" >
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid VerticalAlignment="Top" >
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="20">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="MainWindow1 ViewModel: "/>
                <TextBox Text="{Binding PropWindowViewModel, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold"/>
            </StackPanel>
            <Rectangle Height="10"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="UserControl1 (fixed value Fixed): " VerticalAlignment="Center"/>
                <local:UserControl1 PropUserControlView="Fixed"/>
            </StackPanel>
            <Rectangle Height="10"/>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="UserControl1 (bound to MainWindows VM): " VerticalAlignment="Center"/>
                <local:UserControl1 PropUserControlView="{Binding PropWindowViewModel}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>
我想使用SetBinding将DP绑定到UC VM

这真的是一个要求吗?要求目标属性是依赖项属性,这反过来又要求目标对象是依赖项对象。您的视图模型对象不是依赖项对象,当然,它的任何属性都不是依赖项属性

实现这一目标需要对代码进行比显然需要的更大的更改

如果我将UC数据上下文设置为其VM,则参数绑定不起作用

为什么不呢?您没有显示尝试此操作的代码,因此很难理解此处的含义。无论如何,让用户控件设置自己的
DataContext
不是一个好主意。该属性是公共的,您不希望将实现细节公开给客户端代码。如果客户端代码将
DataContext
设置为错误的内容,那么这样做会导致bug,从而禁用
UserControl
中的所有内容

但是也就是说,如果“参数绑定”是指
main窗口中的绑定
XAML,将
{binding PropWindowViewModel}
分配给用户控件的
PropUserControlView
属性,那么只设置用户控件的
DataContext
就不会影响到这一点。用户控件中仍然有dependency属性,用户控件中绑定的任何内容都应该仍然有效

最后,还不完全清楚为什么要将依赖项属性绑定到视图模型。在用户控件的XAML中,您可以(正如您已经做过的)直接绑定到用户控件的dependency属性。视图模型中不需要属性来复制它

也许您在视图模型的其他地方有代码想要响应此值的更改?这并不清楚,而且在不了解全部情况的情况下,很难给出最好的建议

综上所述,您在上面发布的代码可以进行一些小的修改。首先,您需要公开创建视图模型的
TextBlock
,以便后面的用户控件代码可以访问它:

<TextBlock x:Name="textBlock1" Text="{Binding PropUserControlViewModel, FallbackValue=propUserControlViewModel 2}" FontWeight="Bold">
  <TextBlock.DataContext>
    <l:UserControl1ViewModel/>
  </TextBlock.DataContext>
</TextBlock>
上述方法在您有限的示例中有效,但您可能希望为
dependencPropertyChanged()
方法指定一个更具描述性的名称,具体到所讨论的实际属性


如果您确实选择以这种方式镜像视图模型中的依赖项属性,那么更好的方法是设置用户控件的根元素(即
网格
),使其数据上下文是您的视图模型,然后在XAML的其余部分中,仅绑定到视图模型。混合使用视图模型和依赖属性本身并不是错误的,但它确实引入了不一致性,这会使测试和维护代码变得更加困难。

据我所知,您的意思是:-

1) 您有一个用户控件,它有自己的视图模型

2) 您有一个窗口,其中有自己的视图模型

您希望链接这两个参数,并将参数从WindowViewModel传递到UserControlViewModel

您可以做的是,在WindowViewModel中保留UserControlViewModel类型的属性(例如,
UCViewModel
),并将XAML中用户控件的datacontext设置为

<local:UserControl1 DataContext="{Binding UCViewModel}" .../>

现在,您可以通过WindowViewModel访问UserControlViewModel中的任何内容,您可以设置任何属性值或从WindowViewModel向UserControlViewModel传递任何参数


如果您需要代码参考,请告诉我。我们一直在以类似的方式使用用户控件,它工作得很好。

“窗口和用户控件都有一个视图模型。我想将一个参数从窗口的VM传递到UC的VM。”这首先是错误的方法。UserControl永远不应该有自己的视图模型。相反,它应该公开绑定到“外部”视图模型的依赖项属性,该视图模型通过从其父元素继承值或在XAML中声明UserControl时直接分配DataContext属性传递给UserControl的DataContext。永远不要在自己的XAML或代码隐藏中显式设置UserControl的DataContext。谢谢。我们需要挫折:这对我来说太具体了。我只希望能够有绑定,链接窗口虚拟机与UC虚拟机。设置UC DataContext时,重新传递参数不起作用:请参阅我的问题。我知道有一些解决方法(我已经尝试过你描述的vm.approach),但我想知道绑定在整个过程中是否可以使用。我做了一次快速尝试,但没有成功。你能给出一个代码指针吗?在任何情况下,这都有窗口和UC VM之间的强引用的缺点,因此您无法独立于UC VM使用窗口。
<local:UserControl1 DataContext="{Binding UCViewModel}" .../>