在代码隐藏中定义的绑定对象

时间:2009-11-10 02:39:43

标签: c# .net wpf binding

我有一些在后面的代码中实例化的对象,例如,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>

在codebehind中

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

    public Window1()
    {
        InitializeComponent();
    }
}

假设标题应该变成“ABCDEFG”吧?但它最终没有显示任何内容。

11 个答案:

答案 0 :(得分:116)

有一种更简单的方法可以做到这一点。您可以为Window或UserControl指定一个Name,然后通过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();
    }
}

答案 1 :(得分:93)

您可以为控件,表单等设置DataContext,如下所示:

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

<强>澄清

设置为上述值的数据上下文应该在“拥有”后面代码的任何元素上完成 - 因此对于Window,您应该在Window声明中设置它。

我的示例使用此代码:

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

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

答案 2 :(得分:23)

尽管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}设置当前有效,也值得记住这一点:)

答案 3 :(得分:5)

稍微澄清一下:没有'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>

答案 4 :(得分:1)

定义转换器:

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( );
    }
}

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

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>

然后,例如,如果您的词典中有一个键为“Name”的条目,那么要绑定它:使用

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

答案 5 :(得分:1)

使您的属性“windowname”成为DependencyProperty并保持其余部分。

答案 6 :(得分:0)

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

<ListView ItemsSource="{Binding}" />

这会将ListView绑定到字典。

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

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

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

<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 :(得分:0)

您可以尝试x:参考技巧

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

答案 10 :(得分:0)

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

public partial class MainWindow : Window
{
  public MainWindow()
  {
    this.DataTemplateSelector = new MyDataTemplateSelector();

    InitializeComponent();

    // ... more initializations ...
  }

  public DataTemplateSelector DataTemplateSelector { get; }

  // ... more code stuff ...
}

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

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

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