【问题标题】:Binding objects defined in code-behind绑定在代码隐藏中定义的对象
【发布时间】:2010-12-14 21:19:10
【问题描述】:

我有一些在后面的代码中实例化的对象,例如,XAML 被称为 window.xaml 并且在 window.xaml.cs 中

protected Dictionary<string, myClass> myDictionary;

如何仅使用 XAML 标记将此对象绑定到例如列表视图?

更新:

(这正是我的测试代码):

<Window x:Class="QuizBee.Host.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding windowname}" Height="300" Width="300"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
    </Grid>
</Window>

在代码隐藏中

public partial class Window1 : Window
{
    public const string windowname = "ABCDEFG";

    public Window1()
    {
        InitializeComponent();
    }
}

假设标题应该变成“ABCDEFG”吧?但它最终什么也没显示。

【问题讨论】:

  • 奇怪的是,如果我更改窗口的属性分配顺序,它就不起作用。如果我设置“Title”属性后跟“DataContext”属性,则不会发生绑定。谁能解释一下? schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft.com/winfx/2006/xaml" xmlns:local ="clr-namespace:INotifyPropertyTest" Height="350" Width="525" DataContext= "{Binding RelativeSource={RelativeSource self}}" Title="{Binding WindowName}" >

标签: c# .net wpf binding


【解决方案1】:

在后面的代码中,将窗口的 DataContext 设置为字典。在您的 XAML 中,您可以编写:

<ListView ItemsSource="{Binding}" />

这会将 ListView 绑定到字典。

对于更复杂的场景,这将是MVVM 模式背后的技术子集。

【讨论】:

    【解决方案2】:

    一种方法是创建一个 ObservableCollection (System.Collections.ObjectModel) 并在其中保存您的字典数据。然后你应该能够将 ObservableCollection 绑定到你的 ListBox。

    在你的 XAML 中你应该有这样的东西:

    <ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
    

    【讨论】:

      【解决方案3】:

      您可以像这样为您的控件、表单等设置 DataContext:

      DataContext="{Binding RelativeSource={RelativeSource Self}}"
      

      澄清

      设置为上述值的数据上下文应该在“拥有”后面代码的任何元素处完成——因此对于一个窗口,你应该在窗口声明中设置它。

      我有您使用此代码的示例:

      <Window x:Class="MyClass"
        Title="{Binding windowname}"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Height="470" Width="626">
      

      在此级别设置的 DataContext 然后被窗口中的任何元素继承(除非您为子元素显式更改它),因此在为 Window 设置 DataContext 后,您应该能够直接绑定到 CodeBehind 属性来自窗口上的任何控件。

      【讨论】:

      • 这里的“Self”是指控件,而不是整个窗口类,是吗?
      • 很奇怪,以下是我拥有的代码,但它不能按预期工作: public partial class Window1 : Window { public const string windowname = "ABCDEFG";公共 Window1() { InitializeComponent(); } } schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft.com/winfx/2006/xaml" Title="{Binding windowname}" Height="300" Width="300" DataContext ="{Binding RelativeSource={RelativeSource Self}}">
      • 哦,现在好了,我把windowname改成了property而不是纯public变量,现在可以显示了!谢谢!
      • 我无法想象为什么这不是默认设置的。
      【解决方案4】:

      定义一个转换器:

      public class RowIndexConverter : IValueConverter
      {
          public object Convert( object value, Type targetType,
                                 object parameter, CultureInfo culture )
          {
              var row = (IDictionary<string, object>) value;
              var key = (string) parameter;
              return row.Keys.Contains( key ) ? row[ key ] : null;
          }
      
          public object ConvertBack( object value, Type targetType,
                                     object parameter, CultureInfo culture )
          {
              throw new NotImplementedException( );
          }
      }
      

      绑定到字典的自定义定义。我省略了很多覆盖,但索引器是重要的,因为它会在值更改时发出属性更改事件。这是源到目标绑定所必需的。

      public class BindableRow : INotifyPropertyChanged, IDictionary<string, object>
      {
          private Dictionary<string, object> _data = new Dictionary<string, object>( );
      
          public object Dummy   // Provides a dummy property for the column to bind to
          {
              get
              {
                  return this;
              }
              set
              {
                  var o = value;
              }
          }
      
      
          public object this[ string index ]
          {
              get
              {
                  return _data[ index ];
              }
              set
              {
                  _data[ index ] = value;
                  InvokePropertyChanged( new PropertyChangedEventArgs( "Dummy" ) ); // Trigger update
              }
          }
      
      
      }
      

      在您的 .xaml 文件中使用此转换器。首先引用它:

      <UserControl.Resources>
          <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/>
      </UserControl.Resources>
      

      然后,例如,如果您的字典有一个键为“名称”的条目,那么要绑定到它:使用

      <TextBlock  Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">
      

      【讨论】:

        【解决方案5】:

        将您的属性“windowname”设为 DependencyProperty 并保持其余部分相同。

        【讨论】:

          【解决方案6】:

          虽然 Guy 的回答是正确的(并且可能适合 10 种情况中的 9 种情况),但值得注意的是,如果您尝试从已经将其 DataContext 设置在堆栈更深处的控件执行此操作,您将在以下情况下重置它您将 DataContext 设置回自身:

          DataContext="{Binding RelativeSource={RelativeSource Self}}"
          

          这当然会破坏您现有的绑定。

          如果是这种情况,您应该在您尝试绑定的控件上设置RelativeSource,而不是在其父控件上。

          即用于绑定到 UserControl 的属性:

          Binding Path=PropertyName, 
                  RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
          

          鉴于目前很难看到数据绑定发生了什么,即使您发现设置 RelativeSource={RelativeSource Self} 当前有效,也值得牢记这一点:)

          【讨论】:

          【解决方案7】:

          有一种更简单的方法可以做到这一点。您可以为您的 Window 或 UserControl 分配一个名称,然后通过 ElementName 进行绑定。

          Window1.xaml

          <Window x:Class="QuizBee.Host.Window1"
                  x:Name="Window1"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
          
              <ListView ItemsSource="{Binding ElementName=Window1, Path=myDictionary}" />
          </Window>
          

          Window1.xaml.cs

          public partial class Window1:Window
          {
              // the property must be public, and it must have a getter & setter
              public Dictionary<string, myClass> myDictionary { get; set; }
          
              public Window1()
              {
                  // define the dictionary items in the constructor
                  // do the defining BEFORE the InitializeComponent();
          
                  myDictionary = new Dictionary<string, myClass>()
                  {
                      {"item 1", new myClass(1)},
                      {"item 2", new myClass(2)},
                      {"item 3", new myClass(3)},
                      {"item 4", new myClass(4)},
                      {"item 5", new myClass(5)},
                  }; 
          
                  InitializeComponent();
              }
          }
          

          【讨论】:

          • 我不得不更改 x:Name(编译器错误 CS0542)。然后 ElementName 需要相应地更改。
          【解决方案8】:

          我遇到了同样的问题,但我的问题不是因为我设置了一个局部变量...我在一个子窗口中,我需要设置一个刚刚添加到窗口 XAML 的相对 DataContext。

          <Window x:Class="Log4Net_Viewer.LogItemWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              DataContext="{Binding RelativeSource={RelativeSource Self}}"
              Title="LogItemWindow" Height="397" Width="572">
          

          【讨论】:

            【解决方案9】:

            再澄清一点:没有 'get','set' 的属性将无法绑定

            我正面临这个案子,就像提问者的案子一样。而且我必须具备以下条件才能使绑定正常工作:

            //(1) Declare a property with 'get','set' in code behind
            public partial class my_class:Window {
              public String My_Property { get; set; }
              ...
            
            //(2) Initialise the property in constructor of code behind
            public partial class my_class:Window {
              ...
              public my_class() {
                 My_Property = "my-string-value";
                 InitializeComponent();
              }
            
            //(3) Set data context in window xaml and specify a binding
            <Window ...
            DataContext="{Binding RelativeSource={RelativeSource Self}}">
              <TextBlock Text="{Binding My_Property}"/>
            </Window>
            

            【讨论】:

            • 如果没有“get”和“set”,你怎么能拥有一个属性?那不是字段而不是属性吗?
            【解决方案10】:

            你可以试试 x:Reference 技巧

            <Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
            

            【讨论】:

              【解决方案11】:

              这是我绑定到后面代码的方式(参见属性DataTemplateSelector

              public partial class MainWindow : Window
              {
                public MainWindow()
                {
                  this.DataTemplateSelector = new MyDataTemplateSelector();
              
                  InitializeComponent();
              
                  // ... more initializations ...
                }
              
                public DataTemplateSelector DataTemplateSelector { get; }
              
                // ... more code stuff ...
              }
              

              在 XAML 中,RelativeSource 将通过祖先引用直到包含 Window,所以我在我的 Window 类中并通过 Path 声明使用该属性:

              <GridViewColumn Header="Value(s)"
                              CellTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataTemplateSelector}"/>
              
              

              在调用InitializeComponent 之前设置属性DataTemplateSelector 取决于缺少IPropertyChanged 的实现或使用DependencyProperty 的实现,因此在更改属性DataTemplateSelector 时不会进行通信。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-02-04
                • 1970-01-01
                • 2010-11-19
                • 1970-01-01
                • 2015-12-30
                • 2016-09-12
                • 1970-01-01
                相关资源
                最近更新 更多