C# 如何将UserControl的DependencyProperty绑定到其中的属性';MVVM中的视图模型?

C# 如何将UserControl的DependencyProperty绑定到其中的属性';MVVM中的视图模型?,c#,wpf,xaml,mvvm,user-controls,C#,Wpf,Xaml,Mvvm,User Controls,问题不在于如何让这些东西发挥作用,它已经起作用了;这是关于我正在经历的一些奇怪的行为,我需要理解它。我有一个包含一些样式的ResourceDictionary,其中一个得到了TargetType=“{x:Type UserControl}”和x:Key=“UCStyle”;该选项应用于项目中的多个UserControls。 其中一些UserControls在其ViewModel中获得了string State属性,用于应用可视状态(通过外部类和附加属性,绑定到XAML中的ViewModel)。在

问题不在于如何让这些东西发挥作用,它已经起作用了;这是关于我正在经历的一些奇怪的行为,我需要理解它。我有一个包含一些样式的
ResourceDictionary
,其中一个得到了
TargetType=“{x:Type UserControl}”
x:Key=“UCStyle”
;该选项应用于项目中的多个
UserControl
s。 其中一些
UserControl
s在其ViewModel中获得了
string State
属性,用于应用可视状态(通过外部类和附加属性,绑定到XAML中的ViewModel)。在这之前,一切都很完美,然后,我尝试将
dependencProperty状态添加到
UserControl
,并简单地将其绑定到ViewModel中的State属性,我的尝试是:

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <!--ResourceDictionary Source="..."/-->
        </ResourceDictionary.MergedDictionaries>
        <Style x:Key="MyStyle" TargetType="{x:Type local:MyUserControl}" BasedOn="{StaticResource UCStyle}">
            <Setter Property="State" Value="{Binding State, Mode=TwoWay}"/>
        </Style>
    </ResourceDictionary>
</UserControl.Resources>
<UserControl.Style>
    <DynamicResourceExtension ResourceKey="MyStyle" />
</UserControl.Style>

这在运行时非常有效,但在设计时,它总是在这些行下面划线

并显示一个错误,显示:

“MyUserControl”TargetType与元素“UserControl”的类型不匹配

并且在VisualStudio的XAML查看器中既不应用
UCStyle
也不应用
MyStyle
,甚至不正确地绘制子
UserControl
s。我没料到解决方案会正常运行,但它确实运行了

现在我的问题是:

  • 为什么它在正常运行时在设计时显示这些错误
  • 如何在设计阶段消除这些错误?(我清理并重新构建了解决方案,重新启动了Visual Studio,但所有这些都不起作用)
  • 在MVVM中,在这种情况下处理“UserControl”可视状态的最佳实践是什么
  • 将UserControl的DependencyProperty绑定到MVVM的ViewModel中的属性的最佳实践是什么

我正在使用Visual Studio 2012。

wpf设计器在设计时显示虚假错误是邪恶的。你不能做太多,只能忽略它们

可视状态是UI关注的问题,因此应包含在UI中。MVVM并不意味着没有代码隐藏。将代码隐藏用于UI任务,并将业务逻辑放在视图模型中

您的问题表明您正在创建自定义视图模型以保存用户控件的视图逻辑。说真的,别那么做。那会给你带来麻烦的。它干扰了数据绑定的工作方式

没有将用户控件元素绑定到其表面上定义的属性的“最佳实践”。视情况而定。然而,使用一种风格来实现这一点似乎很奇怪。您只需给UserControl的根一个
x:Name=“root”
,然后在绑定中使用
ElementName=root

UserControl内绑定到UserControl上定义的属性的示例(取自旧原型)

这是一个用户控件,用于添加或删除内容列表

  • UserControl上定义的DependencyProperties
  • UserControl中绑定到这些属性的绑定
我不能保证这是可行的,但它将说明它是如何做到的:

public partial class ItemsEditor : UserControl
{
    #region Items
    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register(
            "Items",
            typeof(IEnumerable<Item>),
            typeof(ItemsEditor),
            new UIPropertyMetadata(null));
    public IEnumerable<Item> Items
    {
        get { return (IEnumerable<Item>)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
    }
    #endregion  
    #region AddItem
    public static readonly DependencyProperty AddItemProperty =
        DependencyProperty.Register(
            "AddItem",
            typeof(ICommand),
            typeof(ItemsEditor),
            new UIPropertyMetadata(null));
    public ICommand AddItem
    {
        get { return (ICommand)GetValue(AddItemProperty); }
        set { SetValue(AddItemProperty, value); }
    }
    #endregion          
    #region RemoveItem
    public static readonly DependencyProperty RemoveItemProperty =
        DependencyProperty.Register(
            "RemoveItem",
            typeof(ICommand),
            typeof(ItemsEditor),
            new UIPropertyMetadata(null));
    public ICommand RemoveItem
    {
        get { return (ICommand)GetValue(RemoveItemProperty); }
        set { SetValue(RemoveItemProperty, value); }
    }        
    #endregion  
    public ItemsEditor()
    {
        InitializeComponent();
    }
}
public分部类ItemsEditor:UserControl
{
#区域项目
公共静态只读从属属性ItemsProperty=
从属属性。寄存器(
“项目”,
类型(IEnumerable),
类型(ItemsEditor),
新的UIPropertyMetadata(空);
公共数字项目
{
get{return(IEnumerable)GetValue(ItemsProperty);}
set{SetValue(ItemsProperty,value);}
}
#端区
#区域附加项
公共静态只读从属属性AddItemProperty=
从属属性。寄存器(
“附加项”,
类型(ICommand),
类型(ItemsEditor),
新的UIPropertyMetadata(空);
公共ICommand附加项
{
获取{return(ICommand)GetValue(AddItemProperty);}
set{SetValue(AddItemProperty,value);}
}
#端区
#区域删除项
公共静态只读从属属性RemoveItemProperty=
从属属性。寄存器(
“RemoveItem”,
类型(ICommand),
类型(ItemsEditor),
新的UIPropertyMetadata(空);
公共ICommand RemoveItem
{
获取{return(ICommand)GetValue(removietemproperty);}
set{SetValue(removietemproperty,value);}
}        
#端区
公共项目编辑器()
{
初始化组件();
}
}
它只是列出了一堆东西,你可以添加一个新的东西或从列表中删除一个东西。以下是xaml中的绑定

<UserControl x:Class="LolPrototype.ItemsEditor"
             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:t="clr-namespace:UCsAndICommands"
             x:Name="root">
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type t:Item}">
            <StackPanel Orientation="Horizontal">
                <Button Command="{Binding RemoveItem, ElementName=root}"
                        CommandParameter="{Binding}">Remove</Button>
                <TextBox Text="{Binding Name}" Width="100"/>
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    <StackPanel>
        <Button Command="{Binding AddItem, ElementName=root}">Add</Button>
        <ItemsControl ItemsSource="{Binding Items, ElementName=root}" />
    </StackPanel>
</UserControl>

去除
添加

显然,您可以在祖先资源的列表之外定义数据模板。关键是要展示如何使用ElementName绑定来绑定UserControl中定义的属性。

wpf设计器在设计时显示虚假错误是邪恶的。你不能做太多,只能忽略它们

可视状态是UI关注的问题,因此应包含在UI中。MVVM并不意味着没有代码隐藏。将代码隐藏用于UI任务,并将业务逻辑放在视图模型中

您的问题表明您正在创建自定义视图模型以保存用户控件的视图逻辑。说真的,别那么做。那会给你带来麻烦的。它干扰了数据绑定的工作方式

没有将用户控件元素绑定到其表面上定义的属性的“最佳实践”。视情况而定。然而,使用一种风格来实现这一点似乎很奇怪。