【问题标题】:Bind Dependency Property, defined in Code-Behind, through Xaml to a Property in the DataContext of a UserControl通过 Xaml 将代码隐藏中定义的依赖属性绑定到 UserControl 的 DataContext 中的属性
【发布时间】:2011-07-04 13:26:21
【问题描述】:

我想使用类似于 here. 的代码我遇到的问题是我想扩展它以允许 XAML 中设置的值使用 {Binding PropertyOfViewModel},如下所示:

<local:TestControl>
  <local:TestControl.TestObject>
    {Binding PropertyOfViewModel}
  </local:TestControl.TestObject>
</local:TestControl>

问题在于“无法转换”{Binding PropertyOfViewModel}“”出错。 TestObject 属性在视图的代码隐藏中定义为依赖属性。

如果我可以让它工作,这将允许我在父控件中编写这样的代码:

<local:TestControl x:Name="myControl" DataContext="{Binding TCViewModel}" />

这意味着在 UserControl 中我还可以绑定到在我的 TCViewModel 中公开的命令和其他项目,并且该控件可以大部分是自包含的,并且所有使用者需要设置 DataContext 属性。


编辑

这是整个控件:

<UserControl x:Class="MyProject.Views.AddClientView"
         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:Views="clr-namespace:MyProject.Views"
         Background="{StaticResource WindowBackgroundBrush}"
         mc:Ignorable="d">

<!-- Comment out from here
   <Views:AddClientView>
    <Views:AddClientView.RenderTransform>
        <ScaleTransform ScaleY="1" />
    </Views:AddClientView.RenderTransform>
    <Views:AddClientView.IsInAcceptDataMode>
        <Binding Path="IsInInputMode"/>
    </Views:AddClientView.IsInAcceptDataMode>
    <Views:AddClientView.ContentTemplate>
        <DataTemplate>
to here -->
            <Grid>
                <Label 
                    Height="25" 
                    Width="306"
                    HorizontalAlignment="Left" 
                    Margin="12,12,0,0" 
                    OverridesDefaultStyle="False" 
                    Style="{DynamicResource CalloutLabel}" 
                    VerticalAlignment="Top" Content="Company Name (Name of Organizational Unit)"/>

                <TextBox Height="23" Margin="12,41,12,0" VerticalAlignment="Top" TabIndex="1" />

                <Button 
                    Style="{DynamicResource LightButton}" 
                    Height="23" Width="75" 
                    HorizontalAlignment="Right" 
                    VerticalAlignment="Bottom" 
                    Margin="0,0,97,12" 
                    TabIndex="4">OK</Button>

                <Button 
                    Style="{DynamicResource LightButton}" 
                    Height="23" Width="75" 
                    HorizontalAlignment="Right" 
                    VerticalAlignment="Bottom" 
                    Margin="0,0,12,12" 
                    Command="{Binding Cancel}"
                    TabIndex="3">Cancel</Button>

                <CheckBox Content="Make Groups" Height="16" IsChecked="True" FlowDirection="RightToLeft" Margin="150,79,12,0" VerticalAlignment="Top" TabIndex="2" />

                <Rectangle Fill="{DynamicResource HeaderBarFill}" Height="5" Margin="0,0,0,0" Stroke="{x:Null}" VerticalAlignment="Bottom" />
            </Grid>
<!-- and here 
        </DataTemplate>
    </Views:AddClientView.ContentTemplate>
</Views:AddClientView>
to here-->

为了让它与建议的代码一起编译,我不得不重新安排我的 xaml,现在它在设计模式下都使 Visual Studio 崩溃,当我运行它时,我在InitializeComponent(); 上得到一个 StackOverflow 异常视图构造函数。


编辑 2

这是将此 UserControl 放在窗口上的代码:

<Views:AddClientView x:Name="AddClient" VerticalAlignment="Top" DataContext="{Binding AddClientVM}">
</Views:AddClientView>

有趣的是:如果我从窗口中删除此代码,它会运行/编译正常。如果我从视图中删除所有&lt;Views:AddClientView...&gt; 类型代码,它也可以正常运行。但没有做我想做的事,因为我无法将我的 DP 绑定到 DataContext。

如果我将 UserControl 更改为以下,一切都可以正常编译,我只是松开了对代码隐藏依赖属性的绑定:

<UserControl 
    x:Class="Mage.Views.AddClientView"
    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:Views="clr-namespace:Mage.Views"
    Background="{StaticResource WindowBackgroundBrush}"
    mc:Ignorable="d"  d:DesignWidth="320" d:DesignHeight="145"
    x:Name="AddClientV"
    MaxHeight="145" MinHeight="145">

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="Show">
                <VisualState.Storyboard>
                    <Storyboard>
                    <DoubleAnimation 
                            Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" 
                            Storyboard.TargetName="AddClientV" 
                            From="0" 
                            To="1" 
                            Duration="0:0:1" />
                    </Storyboard>
                </VisualState.Storyboard>
            </VisualState>

            <VisualState x:Name="Hide">
                <VisualState.Storyboard>
                    <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" 
                        Storyboard.TargetName="AddClientV" 
                        From="1" 
                        To="0" 
                        Duration="0:0:1" />
                    </Storyboard>
                </VisualState.Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Views:AddClientView>
        <Views:AddClientView.RenderTransform>
            <ScaleTransform ScaleY="1" />
        </Views:AddClientView.RenderTransform>
        <Views:AddClientView.IsInAcceptDataMode>
            <Binding Path="IsInInputMode"/>
        </Views:AddClientView.IsInAcceptDataMode>
        <Views:AddClientView.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <Label 
                        Height="25" 
                        Width="306"
                        HorizontalAlignment="Left" 
                        Margin="12,12,0,0" 
                        OverridesDefaultStyle="False" 
                        Style="{DynamicResource CalloutLabel}" 
                        VerticalAlignment="Top" Content="Company Name (Name of Organizational Unit)"/>

                    <TextBox Height="23" Margin="12,41,12,0" VerticalAlignment="Top" TabIndex="1" />

                    <Button 
                        Style="{DynamicResource LightButton}" 
                        Height="23" Width="75" 
                        HorizontalAlignment="Right" 
                        VerticalAlignment="Bottom" 
                        Margin="0,0,97,12" 
                        TabIndex="4">OK</Button>

                    <Button 
                        Style="{DynamicResource LightButton}" 
                        Height="23" Width="75" 
                        HorizontalAlignment="Right" 
                        VerticalAlignment="Bottom" 
                        Margin="0,0,12,12" 
                        Command="{Binding Cancel}"
                        TabIndex="3">Cancel</Button>

                    <CheckBox Content="Make Groups" Height="16" IsChecked="True" FlowDirection="RightToLeft" Margin="150,79,12,0" VerticalAlignment="Top" TabIndex="2" />

                    <Rectangle Fill="{DynamicResource HeaderBarFill}" Height="5" Margin="0,0,0,0" Stroke="{x:Null}" VerticalAlignment="Bottom" />
                </Grid>
            </DataTemplate>
        </Views:AddClientView.ContentTemplate>
    </Views:AddClientView>
</UserControl>

代码隐藏依赖属性:

    public bool IsInAcceptDataMode
    {
        get { return (bool)GetValue(IsInAcceptDataModeProperty); }
        set 
        {
            SetValue(IsInAcceptDataModeProperty, value); 

            if (value)
            {
                VisualStateManager.GoToState(this, "Show", false);
            }
            else
            {
                VisualStateManager.GoToState(this, "Hide", false);
            }
        }
    }

    public static readonly DependencyProperty IsInAcceptDataModeProperty =
        DependencyProperty.Register("IsInAcceptDataMode", typeof(bool), typeof(AddClientView), new UIPropertyMetadata(false, null));

编辑 3

因此,我被告知基于 XAML 的绑定存在问题,我尝试转移到代码隐藏,但仍然无法使其正常工作。因此,我正在寻找一种基于代码隐藏的方法来将我的 DependencyProperty 绑定到 ViewModel 中的项目,该项目指定给我的 UserControl 的 DataContext。

【问题讨论】:

  • 能否显示包含此 UserControl 的视图?我没有注意到您提供的代码有任何问题。
  • 是的,我已经更新了帖子。感谢您迄今为止的帮助。
  • 您所说的代码隐藏依赖属性在哪里?我在代码中没有看到它。
  • 刚刚更新为包含用户控件的 XAML 和代码隐藏 DP。
  • 顺便说一句,您的IsInAcceptDataMode 不正确。此设置器不适用于绑定(不会被调用)。你必须使用依赖属性回调。

标签: .net wpf user-interface binding


【解决方案1】:

如果我理解正确,那么您需要的是标准 MVVM 场景和标准绑定。

可以这样做:

<local:TestControl TestObject="{Binding PropertyOfViewModel}">
</local:TestControl>

或者像这样:

<local:TestControl>
  <local:TestControl.TestObject>
    <Binding Path="PropertyOfViewModel"/>
  </local:TestControl.TestObject>
</local:TestControl>

更新:响应您显示的UserControl 的代码...

您正在做的是在其内部放置一个控件,这显然会给您一个 StackOverflow 异常。 您无需在UserControl 内定义ContentTemplate。您可以直接将内容作为子元素放置:

<UserControl 
    x:Class="Mage.Views.AddClientView"
    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:Views="clr-namespace:Mage.Views"
    Background="{StaticResource WindowBackgroundBrush}"
    mc:Ignorable="d"  d:DesignWidth="320" d:DesignHeight="145"
    x:Name="AddClientV"
    MaxHeight="145" MinHeight="145">

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="Show">
                <VisualState.Storyboard>
                    <Storyboard>
                    <DoubleAnimation 
                            Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" 
                            Storyboard.TargetName="AddClientV" 
                            From="0" 
                            To="1" 
                            Duration="0:0:1" />
                    </Storyboard>
                </VisualState.Storyboard>
            </VisualState>

            <VisualState x:Name="Hide">
                <VisualState.Storyboard>
                    <Storyboard>
                    <DoubleAnimation 
                        Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" 
                        Storyboard.TargetName="AddClientV" 
                        From="1" 
                        To="0" 
                        Duration="0:0:1" />
                    </Storyboard>
                </VisualState.Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    <Views:AddClientView.RenderTransform>
            <ScaleTransform ScaleY="1" />
    </Views:AddClientView.RenderTransform>
    <Views:AddClientView.IsInAcceptDataMode>
            <Binding Path="IsInInputMode"/>
    </Views:AddClientView.IsInAcceptDataMode>

   <Grid>
      <Label 
        Height="25" 
        Width="306"
        HorizontalAlignment="Left" 
        Margin="12,12,0,0" 
        OverridesDefaultStyle="False" 
        Style="{DynamicResource CalloutLabel}" 
        VerticalAlignment="Top" Content="Company Name (Name of Organizational Unit)"/>

    <TextBox Height="23" Margin="12,41,12,0" VerticalAlignment="Top" TabIndex="1" />

    <Button 
        Style="{DynamicResource LightButton}" 
        Height="23" Width="75" 
        HorizontalAlignment="Right" 
        VerticalAlignment="Bottom" 
        Margin="0,0,97,12" 
        TabIndex="4">OK</Button>

    <Button 
        Style="{DynamicResource LightButton}" 
        Height="23" Width="75" 
        HorizontalAlignment="Right" 
        VerticalAlignment="Bottom" 
        Margin="0,0,12,12" 
        Command="{Binding Cancel}"
        TabIndex="3">Cancel</Button>

    <CheckBox Content="Make Groups" Height="16" IsChecked="True" FlowDirection="RightToLeft" Margin="150,79,12,0" VerticalAlignment="Top" TabIndex="2" />

    <Rectangle Fill="{DynamicResource HeaderBarFill}" Height="5" Margin="0,0,0,0" Stroke="{x:Null}" VerticalAlignment="Bottom" />
  </Grid>
</UserControl>

【讨论】:

  • 在我运行项目时添加该代码会给我一个 StackOverflow 异常。我正在从我的控件中删除名称规范(只有几行),我将发布整个内容,也许我拥有的其他内容存在冲突并导致我的问题。
  • 非常感谢您花时间在这方面。使用您更新的代码,VS 不再崩溃,并且我不再获得 StackOverflow.... 但我必须删除 Views:AddClientView.. 代码才能编译,错误是:可附加属性“RenderTransform”不是在“AddClientView”类型中找到。 -- IsInAcceptDataMode 出现同样的错误。有什么想法吗?
  • @Nate - 是的...只记得从其 XAML 指定自定义用户控件中定义的属性存在一个已知问题...您将无法做到这一点。相反,您必须从代码隐藏设置此绑定,例如在构造函数中:SetBinding(IsInAcceptDataModeProperty, "IsInInputMode")。至于 RenderTransoform,只需将 替换为 即可。
  • 谢谢!我要试一试,如果/何时修复,有什么消息吗?
  • 不喜欢构造函数中的SetBinding(IsInAcceptDataModeProperty, "IsInInputMode"),但我会继续探索。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-18
  • 2019-06-07
  • 2013-10-17
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多