如何重用WPF用户控件但更改绑定属性?

时间:2017-10-08 14:00:17

标签: c# wpf xaml mvvm devexpress

我有一个WPF用户控件,它使用我的viewmodel中的属性进行绑定。我现在想要使用具有相同viewmodel的该用户控件的两个实例,但是覆盖其中一个的绑定。

代码看起来像这样

用户控制

<UserControl x:Class="TestWpfApp.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TestWpfApp">
    <Grid>
        <DockPanel>
            <Label Margin="10" Content="{Binding MyLabel}"/>
            <Button Margin="10" Content="{Binding MyButton}"/>
        </DockPanel>
    </Grid>
</UserControl>

主视图

<Window x:Class="TestWpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestWpfApp"
        Title="MainWindow" Height="150" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <DockPanel>
            <local:UserControl1 DockPanel.Dock="Top" x:Name="UserControl1"/>
            <!--In this instance of UserControl1, I want the Label to bind to the MyNewLabel-->
            <local:UserControl1 DockPanel.Dock="Top" x:Name="UserControl2"/>
        </DockPanel>
    </Grid>
</Window>

视图模型

public class ViewModel
{
    public string MyLabel => "Label1";
    public string MyButton => "Button1";
    public string MyNewLabel => "Label2";
}

UserControl1的第二个实例中,我希望标签绑定到不同的属性。我尝试将该属性设置为用户控件上的资源,然后在主视图中覆盖它,但我无法使其工作。

实际上,我正在使用DevExpress控件和POCO视图模型,如果这更容易。

1 个答案:

答案 0 :(得分:7)

创建自定义控件时 - 将自定义控件中的控件绑定到外部数据上下文提供的任意属性并不是一个好主意。您不仅会遇到类似于现在的问题,该控件的用户也不知道哪个datacontext应该为该控件提供哪些属性。只查看UserControl的源代码,可能会发现它需要具有属性MyLabelMyButton的数据上下文。相反 - 通过在控件本身上引入依赖属性来使控件自包含:

public partial class UserControl1 : UserControl {
    public UserControl1() {
        InitializeComponent();
    }

    public string Text
    {
        get { return (string) GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new PropertyMetadata(null));

    public string ButtonText
    {
        get { return (string) GetValue(ButtonTextProperty); }
        set { SetValue(ButtonTextProperty, value); }
    }

    public static readonly DependencyProperty ButtonTextProperty =
        DependencyProperty.Register("ButtonText", typeof(string), typeof(UserControl1), new PropertyMetadata(null));
}

并绑定到这些属性:

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                          
             x:Name="self">
    <Grid>
        <DockPanel>
            <Label Margin="10"
                   Content="{Binding Text, ElementName=self}" />
            <Button Margin="10"
                    Content="{Binding ButtonText, ElementName=self}" />
        </DockPanel>
    </Grid>
</UserControl>

然后在主窗口中 - 将这些依赖项属性绑定到您的模型:

<Window.DataContext>
    <my:ViewModel />
</Window.DataContext>
<Grid>
    <DockPanel>
        <my:UserControl1 DockPanel.Dock="Top"
                            x:Name="UserControl1" Text="{Binding MyLabel}" ButtonText="{Binding MyButton}" />
        <!--In this instance of UserControl1, I want the Label to bind to the MyNewLabel-->
        <my:UserControl1 DockPanel.Dock="Top"
                         x:Name="UserControl2"
                         Text="{Binding MyNewLabel}"
                         ButtonText="{Binding MyButton}" />
    </DockPanel>
</Grid>