我有一些在后面的代码中实例化的对象,例如,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”吧?但它最终没有显示任何内容。
答案 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}时不会进行任何通信}。