绑定的几种用法

最基本的绑定(必须在一个可视化树中间,例如后台代码生成就不行)

<StackPanel>
    <TextBlock Text="{Binding ElementName=txt,Path=Text,StringFormat='Input:{0}'}"/>
    <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=StackPanel},Path=Children[2].Text,StringFormat='Input:{0}'}"/>
    <TextBox x:Name="txt"/>

</StackPanel>

如果是后台代码生成的话,需要添加控件到NameScope中

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    var box = new TextBox
    {
        Name = "txt"
    };
    this.RegisterName(box.Name, box);
    panel.Children.Add(box);
}
 <StackPanel x:Name="panel">
     <TextBlock Text="{Binding ElementName=txt,Path=Text,StringFormat='Input:{0}'}"/>
     // 这行不起作用的原因是越界了
     <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=StackPanel},Path=Children[2].Text,StringFormat='Input:{0}'}"/>
     <!--<TextBox x:Name="txt"/>-->

 </StackPanel>

绑定失败原因:因为在可视化树中找不到Button.Tag、DataGrid.Columns(直接不显示)

 <StackPanel x:Name="panel">
     <TextBlock Name="tbl" Text="Hello world!"/>
     <Button HorizontalAlignment="Center">
         <Button.Tag>
             <ItemsControl>
                 <TextBlock Text="{Binding ElementName=tbl,Path=Text}"/>
                 <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=StackPanel},Path=Children[0].Text}"/>
             </ItemsControl>
         </Button.Tag>
     </Button>
     <DataGrid>
	    <DataGrid.Columns>
	        <DataGridTextColumn Header="{Binding ElementName=tbl,Path=Text}"/>
	    </DataGrid.Columns>
	</DataGrid>
 </StackPanel>

解决方法:将绑定换为Source={x:Reference Name=tbl},Path=Text
原因:使用x:Reference

 <Button.Tag>
     <ItemsControl>
         <TextBlock Text="{Binding ElementName=tbl,Path=Text}"/>
         <TextBlock Text="{Binding Source={x:Reference Name=tbl},Path=Text}"/>
     </ItemsControl>
 </Button.Tag>

使用x:Reference有个弊端:存在循环依赖无法被解析
以下面例子举例,在button还没有被解析完,就不能绑定到它身上

 <Button x:Name="tbn" HorizontalAlignment="Center" Content="Click Me">
     <Button.Tag>
         <ItemsControl>
             <TextBlock Text="{Binding Source={x:Reference Name=tbn},Path=Content}"/>
         </ItemsControl>
     </Button.Tag>
 </Button>

特殊情况,内容(MenuItem)跑到可视化树的其他地方(这个控件的作用是右键点出东西)
同样情况还有ToolTip属性(这个属性的作用是鼠标悬空后,弹出相应信息)(如果直接写在button的属性里,也可以直接显示出来)
上述属性在可视化树里面都是在PopupRoot里

 <Button x:Name="tbn" HorizontalAlignment="Center" Content="Click Me">
     <Button.ContextMenu>
         <ContextMenu Name="context">
             <MenuItem Name="menuitem" Header="{Binding ElementName=tbl,Path=Text}"/>
         </ContextMenu>
     </Button.ContextMenu>
 </Button>

解决方法1:使用x:Reference
解决方法2:将datacontext=viewmodel,直接绑定对应属性(xxx= “{Binding Message}”)
解决方法3:通过RelativeSource来访问

<Button x:Name="tbn" HorizontalAlignment="Center" Content="Click Me">
    <Button.ContextMenu>
        <ContextMenu Name="context">
            <MenuItem Name="menuitem" Header="{Binding Source={x:Reference Name=tbl},Path=Text}"/>
        </ContextMenu>
    </Button.ContextMenu>
</Button>
<Button x:Name="tbn" HorizontalAlignment="Center" Content="Click Me">
    <Button.ToolTip>
        <ToolTip>
            <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ToolTip},Path=PlacementTarget.Content}"/>
        </ToolTip>
    </Button.ToolTip>
    
    <Button.ContextMenu>
        <ContextMenu Name="context">
            <MenuItem Name="menuitem" Header="{Binding Source={x:Reference Name=tbl},Path=Text}"/>
        </ContextMenu>
    </Button.ContextMenu>
</Button>

传递参数的时候尽量使用RelativeSource而不是ElementName

// 这个代码起作用
 <Button.ContextMenu>
     <ContextMenu Name="context">
         <MenuItem Name="menuitem" Header="Foo" Command="{Binding FooCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
     </ContextMenu>
 </Button.ContextMenu>
// 这段代码不起作用
 <Button.ContextMenu>
      <ContextMenu Name="context">
          <MenuItem Name="menuitem" Header="Foo" Command="{Binding FooCommand}" CommandParameter="{Binding ElementName=context}"/>
      </ContextMenu>
  </Button.ContextMenu>

万能方法1(BIndingProxy要更加轻量)
万能方法2()

首先创建一个类BindingProxy

 public class BindingProxy : Freezable
 {
     protected override Freezable CreateInstanceCore() => new BindingProxy();

     public object Data
     {
         get => GetValue(DataProperty);
         set => SetValue(DataProperty, value);
     }

     public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
         nameof(Data),
         typeof(object),
         typeof(BindingProxy)
     );

 }

然后再在xmal中引用

 <Window.Resources>
 	// 首先要加入资源里面
     <local:BindingProxy x:Key="MyButton" Data="{Binding ElementName=btn}"/>
 </Window.Resources>

 <StackPanel x:Name="panel">
     
     <TextBlock Name="tbl" Text="Hello world!"/>
     <Button x:Name="btn" HorizontalAlignment="Center" Content="Click Me!!!">
         <Button.ToolTip>
             <ToolTip>
             	// 在这里引用
                 <TextBlock Text="{Binding Source={StaticResource MyButton},Path=Data.Content}"/>
             </ToolTip>
         </Button.ToolTip>
 </StackPanel>

方法二

<Window.Resources>
    <local:BindingProxy x:Key="MyButton" Data="{Binding ElementName=btn}"/>
    // 这里添加引用
    <DiscreteObjectKeyFrame x:Key="KeyFrame" Value="{Binding ElementName=window}"/>
</Window.Resources>

<StackPanel x:Name="panel">
    
    <TextBlock Name="tbl" Text="Hello world!"/>
    <Button x:Name="btn" HorizontalAlignment="Center" Content="Click Me!!!">
        <Button.ToolTip>
            <ToolTip>
                <TextBlock Text="{Binding Source={StaticResource MyButton},Path=Data.Content}"/>
            </ToolTip>
        </Button.ToolTip>
        
        <Button.ContextMenu>
            <ContextMenu Name="context">
            	// 在这里使用
                <MenuItem Name="menuitem" Header="Foo" Command="{Binding Source={StaticResource KeyFrame},Path=Value.DataContext.FooCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
            </ContextMenu>
        </Button.ContextMenu>
    </Button>
</StackPanel>

笨方法:在后台进行绑定

 public partial class MainWindow : Window
 {
     public MainWindow()
     {
         InitializeComponent();
     }



     private void Window_Loaded(object sender, RoutedEventArgs e)
     {
         var binding = new Binding()
         {
             Source = tbl,
             Path = new PropertyPath(TextBlock.TextProperty)
         };
         // 绑定方法1
         BindingOperations.SetBinding(menuitem,MenuItem.HeaderProperty, binding);
         // 绑定方法2
         menuitem.SetBinding(MenuItem.HeaderProperty, binding);
     }
 }
<StackPanel x:Name="panel">
    
    <TextBlock Name="tbl" Text="Hello world!"/>
    <Button x:Name="btn" HorizontalAlignment="Center" Content="Click Me!!!">
        <Button.ToolTip>
            <ToolTip>
                <TextBlock Text="{Binding Source={StaticResource MyButton},Path=Data.Content}"/>
            </ToolTip>
        </Button.ToolTip>
        
        <Button.ContextMenu>
            <ContextMenu Name="context">
                <MenuItem Name="menuitem"
                          Command="{Binding Source={StaticResource KeyFrame},Path=Value.DataContext.FooCommand}" 
                          CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
            </ContextMenu>
        </Button.ContextMenu>
    </Button>
</StackPanel>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值