【问题标题】:Is it possible to bind code-behind property without setting DataContext?是否可以在不设置 DataContext 的情况下绑定代码隐藏属性?
【发布时间】:2012-03-07 01:31:37
【问题描述】:

正如标题, 我在 SO 中看到了几个类似的问题 thisthis,但我没有看到解决方案。

知道是否需要绑定code-beind,需要设置Datacontext = this

但我的问题是我的数据上下文已经绑定到我的 ViewModel,但我想使用代码中定义的 Command 进行一些 UI 操作。

是否可以在 xaml 中绑定它?如果有,怎么做?

编辑:我确实尝试了以下方法:

<Window x:Class="WpfApplication3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" x:Name="_Root">
<Grid x:Name="hellogrid">
    <TextBlock x:Name="myTextBlock" Text="AAAA"/>
    <Button Margin="82,119,121,120" Name="button2" Content="{Binding Path=Text, ElementName=myTextBlock}"/>
    <Button Margin="82,72,121,0" Name="button3" Content="{Binding Path=MyText, ElementName=_Root}" Height="23" VerticalAlignment="Top" />
</Grid>

还有代码隐藏:

public partial class Window1 : Window
{
    public string MyText { get; set; }

    public Window1()
    {
        InitializeComponent();
        MyText = "ABC";
    }
}

我可以看到 Button2 显示 AAAA,但 Button3 什么也没显示....

【问题讨论】:

  • 请查看我更新的答案,我刚刚测试过,绑定 button3 内容属性的方式工作正常,如果您需要在运行时更改 MyText 属性,您只需要实现更改通知...

标签: wpf xaml


【解决方案1】:

编辑

IMO 的最佳解决方案是 @Saad Imran 在此 SO question 中的 posted...

使用此解决方案,您只需为窗口命名,然后绑定到 XAML 中的属性将像 {Binding ElementName=MyWindowName, Path=MyText} 一样简单

所以,您对 Content="{Binding Path=MyText, ElementName=_Root}" 所做的事情是完全正确的,并且您的 Button Content 属性已绑定到 MyText 属性,但您唯一缺少的是更改通知(需要为此实现 INotifyPropertyChanged 接口)所以当您将您的 MyText 属性设置为 ABC MyText = "ABC"; 不会发送更改通知...

测试这一点的简单方法是显式设置 MyText 属性:

private string myText = "ABC";
public string MyText
{
   get { return myText; }
   set { myText = value; }
}

或者在调用InitializeComponent()之前在构造函数中设置:

MyText = "ABC";
InitializeComponent();

如果您这样做,您会注意到您的按钮将 ABC 作为其内容,但对 MyText 属性的更改不会影响按钮内容,因为没有更改通知...

【讨论】:

  • 啊,我明白了,这就是我失踪的原因。它现在工作得很好。非常感谢!
【解决方案2】:

当然

有许多类型的绑定。最基本的绑定到DataContext上的一个属性,通常继承自Parent对象

<DataTemplate DataType="{x:Type MyModel}">
    <!-- DataContext is object of type MyModel -->
    <local:MyView />
</DataTemplate>

或者

<Window x:Name="MyWindow">
    <!-- DataContext Inherited from Window -->
    <TextBlock Text="{Binding SomeProperty}" /> 
</Window>

在哪里

var SomeObject = new SomeModel();
SomeObject.SomeProperty = "Test";
myWindow.DataContext = SomeObject;

其他绑定类型包括ElementName,您可以在其中指定目标 UI 元素以用作绑定的数据源

<StackPanel>
    <CheckBox x:Name="SomeCheckBox" />
    <TextBlock Text="{Binding ElementName=SomeCheckBox, Path=IsChecked}" />
</StackPanel>

<local:MyUserControl x:Name="SomeUserControl">
    <Button Command="{Binding ElementName=SomeUserControl, Path=DataContext.SaveCommand}" />
</local:MyUserControl >

RelativeSource,它允许您找到一个相对于当前对象的对象以用作数据源

<Window Title="Test">
    <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Title}" />
</Window>

<local:MyUserControl>
    <Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=DataContext.SaveCommand}" />
</local:MyUserControl >

TemplateBinding 是绑定到模板化对象的RelativeSource 绑定的快捷方式

<Button Content="Test">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <TextBlock Text="{TemplateBinding Content}" />
        </ControlTemplate>
    </Button.Template>
</Button>

【讨论】:

  • 感谢您的推荐!我也让它与你的 RelativeSource 一起工作。但是奇怪,我用RelativeSource AncestorType={x:Type Window}的时候怎么不需要INotifyPropertyChanged?
  • @DeanKuga 在添加代码之前我并不清楚实际问题是什么,并将其读作“我可以绑定到某些东西而不在 DataContext 中指定它”。这似乎是一个宽泛的问题,所以我写了一个宽泛的答案:) 添加代码后,我可以清楚地看到 OP 试图完成什么,但到那时已经发布了一个包含他需要的信息的答案。
  • @Rachel 我什么时候应该使用带有元素名称的绑定,该元素名称绑定到带有窗口名称的窗口,什么时候应该使用带有 RelativeSource 的绑定?他们似乎在做同样的事情
  • @YonatanNir 通常,如果可能的话,我更喜欢使用ElementName 绑定,因为它们更容易理解,但有时您必须绑定到可视化树更上方的未命名元素。一个常见的例子是ListBoxItemTemate 中的一个项目需要绑定它所属的ListBoxItem。通常绑定ListBox,因此ListBoxItems 是自动生成的并且没有名称,因此通常使用RelativeSoruce 绑定来代替
【解决方案3】:

当然,你可以使用ElementName:

<Window Name="root"
        Class="..."
        ...>

    ...

    <TextBox Text="{Binding Path=Foo, ElementName=root}" />

你也可以用RelativeSource来做,但是语法更丑……

【讨论】:

  • 奇怪,我确实尝试了ElementNameBinding Path=Foo, RelativeSource={RelativeSource Self},但都不起作用。我使用的是 WPF 3.5,这有关系吗?
  • @KingChan,这是因为您在调用InitializeComponent 之后 设置了MyText 属性,所以在您更改之前已经检索了该值。由于您的类没有实现INotifyPropertyChanged,并且您的属性不是依赖属性,因此绑定引擎无法知道值已更改,因此它不会刷新按钮的内容。
猜你喜欢
  • 1970-01-01
  • 2012-08-21
  • 1970-01-01
  • 2019-06-16
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 2022-11-12
  • 2011-01-03
相关资源
最近更新 更多