绑定在后台代码中定义的对象


88

我有一些在代码后实例化的对象,例如,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”,对吗?但最终什么也没显示。


1
奇怪的是,如果我更改窗口的属性分配顺序,则无法正常工作。如果我先设置“ Title”属性,再设置“ DataContext”属性,则不会发生绑定。谁能解释一下?<Window x:Class =“ INotifyPropertyTest.MainWindow” xmlns =“ 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}“>
Ramesh

Answers:


109

您可以为控件,表单等设置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 属性在窗户上。


1
这里的“ Self”是指控件,而不是整个窗口类,是吗?
xandy

奇怪的是,以下是我拥有的代码,它无法按预期工作:public部分类Window1:Window {public const string windowname =“ ABCDEFG”; 公共Window1(){InitializeComponent(); }} <Window x:Class =“ QuizBee.Host.Window1” xmlns =“ schemas.microsoft.com/winfx/2006/xaml/presentation ” xmlns:x =“ schemas.microsoft.com/winfx/2006/xaml ”标题=“ {Binding windowname}” Height =“ 300” Width =“ 300” DataContext =“ {Binding RelativeSource = {RelativeSource Self}}”> </ Window>
xandy

9
哦,现在可以了,我将windowname更改为属性,而不是纯公共变量,它现在可以显示!谢谢!
xandy

1
我无法想象为什么这不是默认设置。
Okonomiyaki3000 '18

122

有一种更简单的方法可以做到这一点。您可以将名称分配给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();
    }
}

3
我必须更改x:Name(编译器错误CS0542)。然后,需要相应地更改ElementName。
杰克·米勒

25

尽管盖伊的答案是正确的(可能适合10个案例中的9个),但值得注意的是,如果您尝试从已经将其DataContext设置在堆栈上方的控件中执行此操作,则在设置DataContext时将对其进行重置回到本身:

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

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

在这种情况下,应在要绑定的控件上设置RelativeSource,而不是在其父控件上设置。

即用于绑定到UserControl的属性:

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

考虑到当前查看数据绑定的情况可能有多么困难,即使您发现该设置RelativeSource={RelativeSource Self}当前有效,也应牢记这一点:)


1
Silverlight 4不支持FindAncestor。但是,您需要以这种方式执行此操作,才能实现此站点上所述的FindAncestor。http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
ShawnFeatherly 2011年

7

再澄清一下:没有“ 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>

9
没有“ get”和“ set”,您怎么能拥有一个财产?那不是领域而不是财产吗?
kjbartel 2014年

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

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

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}">

1

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


0

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

<ListView ItemsSource="{Binding}" />

这会将ListView绑定到字典。

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


0

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

在您的XAML中,您应该具有以下内容:

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

0

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

<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">

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.