C# 代码隐藏中定义的绑定对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1705322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:07:17  来源:igfitidea点击:

Binding objects defined in code-behind

c#.netwpfbinding

提问by xandy

I have some object that is instantiated in code behind, for instance, the XAML is called window.xaml and within the window.xaml.cs

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

protected Dictionary<string, myClass> myDictionary;

How can I bind this object to, for example, a list view, using only XAML markups?

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

Update:

更新:

(This is exactly I have in my test code):

(这正是我在我的测试代码中所拥有的):

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

And in codebehind

在代码隐藏中

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

    public Window1()
    {
        InitializeComponent();
    }
}

Suppose the title should become "ABCDEFG" right? but it ends up showing nothing.

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

采纳答案by Guy Starbuck

You can set the DataContext for your control, form, etc. like so:

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

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

Clarification:

澄清

The data context being set to the value above should be done at whatever element "owns" the code behind -- so for a Window, you should set it in the Window declaration.

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

I have your example working with this code:

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

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

The DataContext set at this level then is inherited by any element in the window (unless you explicitly change it for a child element), so after setting the DataContext for the Window you should be able to just do straight binding to CodeBehind propertiesfrom any control on the window.

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

回答by Szymon Rozga

In your code behind, set the window's DataContext to the dictionary. In your XAML, you can write:

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

<ListView ItemsSource="{Binding}" />

This will bind the ListView to the dictionary.

这会将 ListView 绑定到字典。

For more complex scenarios, this would be a subset of techniques behind the MVVMpattern.

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

回答by Partial

One way would be to create an ObservableCollection (System.Collections.ObjectModel) and have your dictionary data in there. Then you should be able to bind the ObservableCollection to your ListBox.

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

In your XAML you should have something like this:

在您的 XAML 中,您应该有这样的内容:

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

回答by Phillip Ngan

Define a converter:

定义转换器:

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

Bind to a custom definition of a Dictionary. There's lot of overrides that I've omitted, but the indexer is the important one, because it emits the property changed event when the value is changed. This is required for source to target binding.

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

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


}

In your .xaml file use this converter. First reference it:

在您的 .xaml 文件中使用此转换器。先参考一下:

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

Then, for instance, if your dictionary has an entry where the key is "Name", then to bind to it: use

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

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

回答by viky

Make your property "windowname" a DependencyProperty and keep the remaining same.

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

回答by CatBusStop

While Guy's answer is correct (and probably fits 9 out of 10 cases), it's worth noting that if you are attempting to do this from a control that already has its DataContext set further up the stack, you'll resetting this when you set DataContext back to itself:

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

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

This will of course then break your existing bindings.

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

If this is the case, you should set the RelativeSource on the control you are trying to bind, rather than its parent.

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

i.e. for binding to a UserControl's properties:

即绑定到用户控件的属性:

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

Given how difficult it can be currently to see what's going on with data binding, it's worth bearing this in mind even if you find that setting RelativeSource={RelativeSource Self}currently works :)

鉴于目前查看数据绑定的情况有多么困难,即使您发现该设置RelativeSource={RelativeSource Self}当前有效,也值得牢记这一点:)

回答by Saad Imran.

There's a much easier way of doing this. You can assign a Name to your Window or UserControl, and then binding by ElementName.

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

Window1.xaml

窗口1.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

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

回答by davesbrain

I was having this exact same problem but mine wasn't because I was setting a local variable... I was in a child window, and I needed to set a relative DataContext which I just added to the Window XAML.

我遇到了完全相同的问题,但我的不是因为我正在设置一个局部变量......我在一个子窗口中,我需要设置一个我刚刚添加到 Window 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">

回答by jondinham

Just a little more clarification: A property without 'get','set' won't be able to be bound

再澄清一点:没有“get”、“set”的属性将无法绑定

I'm facing the case just like the asker's case. And I must have the following things in order for the bind to work properly:

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

//(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>

回答by Николай Солдаткин

You can try x:Reference trick

你可以试试 x:Reference 技巧

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