我有一个MainWindow:Window
类,它包含我程序中的所有数据。 MainWindow
的.xaml只包含一个动态填充的空TabControl(在代码隐藏中)。
其中一个标签(OptionsTab
)将.DataContext
定义为MainWindow
,授予其访问所有数据的权限。 OptionsTab
有一个DataGrid
,其中有一列填充了Buttons
,如下所示:
DataGrid
填充了DataGridTemplateColumns
,其中DataTemplate
在主<Grid.Resources>
中定义。我想将此按钮绑定到MainWindow
中的函数(而不是它所在的OptionsTab
)。
创建OptionsTab
后,.DataContext
被MainWindow
设置为DataTemplate
,因此我原本希望定义<DataTemplate x:Key="DeadLoadIDColumn">
<Button Content="{Binding Phases, Path=DeadLoadID}" Click="{Binding OpenDeadLoadSelector}"/>
</DataTemplate>
如下所示。< / p>
OptionsTab.DataContext = MainWindow's
我认为这意味着Click事件将绑定到所需的Content
函数。但是,这不起作用(Command
确实如此)。然后我开始查找并查看this answer to another SO question(由Rachel撰写,他的博客对我有很大的帮助),我从中了解到你无法将click事件{绑定}到方法,但必须而是将ICommand
属性绑定到RelayCommand
属性(使用帮助器DeadClick
类),这会将您引入所需的方法。所以我实现了它,但它没有用。如果我在OpenDeadLoadSelector()
getter或<Window x:Class="WPF.MainWindow"
x:Name="Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF" SizeToContent="WidthAndHeight">
<TabControl Name="tabControl"
SelectedIndex="1"
ItemsSource="{Binding Tabs, ElementName=Main}">
</TabControl>
</Window>
上放置调试断点并运行程序,单击按钮不会触发任何内容,这意味着{Binding}不起作用。
我想知道这是否是我的误解,或者我是否在我的代码实现中做了一些错误,随后(不相关的代码被删除):
MainWindow.xaml
public partial class MainWindow : Window
{
ICommand deadClick;
public ICommand DeadClick
{
get
{
if (null == deadClick)
deadClick = new RelayCommand(p => OpenDeadLoadSelector());
return deadClick;
}
}
public ObservableCollection<TabItem> Tabs = new ObservableCollection<TabItem>();
public static DependencyProperty TabsProperty = DependencyProperty.Register("Tabs", typeof(ICollectionView), typeof(MainWindow));
public ICollectionView ITabsCollection
{
get { return (ICollectionView)GetValue(TabsProperty); }
set { SetValue(TabsProperty, value); }
}
public ObservableCollection<NPhase> Phases = new ObservableCollection<NPhase>();
public static DependencyProperty PhasesProperty = DependencyProperty.Register("Phases", typeof(ICollectionView), typeof(MainWindow));
public ICollectionView IPhasesCollection
{
get { return (ICollectionView)GetValue(PhasesProperty); }
set { SetValue(PhasesProperty, value); }
}
public ObservableCollection<string> Loads = new ObservableCollection<string>();
public static DependencyProperty LoadsProperty = DependencyProperty.Register("Loads", typeof(ICollectionView), typeof(MainWindow));
public ICollectionView ILoadsCollection
{
get { return (ICollectionView)GetValue(LoadsProperty); }
set { SetValue(LoadsProperty, value); }
}
void OpenDeadLoadSelector()
{
int a = 1;
}
public MainWindow()
{
var optionsTab = new TabItem();
optionsTab.Content = new NOptionsTab(this);
optionsTab.Header = (new TextBlock().Text = "Options");
Tabs.Add(optionsTab);
ITabsCollection = CollectionViewSource.GetDefaultView(Tabs);
Loads.Add("AS");
Loads.Add("2");
InitializeComponent();
}
}
MainWindow.xaml.cs
<UserControl x:Class="WPF.NOptionsTab"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
xmlns:l="clr-namespace:WPF">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="DeadLoadIDColumn">
<Button Content="{Binding Phases, Path=DeadLoadID}" Command="{Binding Path=DeadClick}"/>
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<!-- ... -->
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<!-- ... -->
</Grid>
<Grid Grid.Row="1">
<!-- ... -->
</Grid>
<l:NDataGrid Grid.Row="2"
x:Name="PhaseGrid"
AutoGenerateColumns="False">
<l:NDataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<DataGridTextColumn Header="Date (days)" Binding="{Binding Path=Date}"/>
<DataGridTemplateColumn Header="Deadload" CellTemplate="{StaticResource DeadLoadIDColumn}"/>
</l:NDataGrid.Columns>
</l:NDataGrid>
</Grid>
</UserControl>
OptionsTab.xaml
public NOptionsTab(MainWindow w)
{
DataContext = w;
InitializeComponent();
PhaseGrid.ItemsSource = w.Phases;
}
OptionsTab.xaml.cs
{Binding Phases, Path=DeadLoadID}
虽然我们正处于此状态(这可能是一个相关的问题),为什么DataTemplate
会对{Binding Phases, Path=Name}
起作用(这就是为什么按钮会出现“选择”),但如果我在PhaseGrid中执行.ItemsSource
并从构造函数中删除DataContext
代码,没有任何反应? PhaseGrid不应该继承其父级(NOptionsTab / Grid)PhaseGrid.DataContext = w;
吗?如果没有.ItemsSource
代码,即使设置NPhase
也没有做任何事情。
编辑(2014年4月27日):
我认为知道public class NPhase : INotifyPropertyChanged
{
string name;
double date;
string deadLoadID = "Select";
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get { return name; }
set
{
name = value;
EmitPropertyChanged("Name");
}
}
public double Date
{
get { return date; }
set
{
date = value;
EmitPropertyChanged("Date");
}
}
public string DeadLoadID
{
get { return deadLoadID; }
set
{
deadLoadID = value;
EmitPropertyChanged("DeadLoadID");
}
}
void EmitPropertyChanged(string property)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public NPhase(double _date, string _name)
{
date = _date;
name = _name;
}
}
类本身的内容是有用的,所以这里是:
{{1}}
编辑(2014年4月29日):
可以从这里下载简化项目(摆脱不必要的一切)(https://dl.dropboxusercontent.com/u/3087637/WPF.zip)
答案 0 :(得分:1)
我认为存在一个问题,即您没有为网格中的数据项正确指定数据源。
我认为按钮列的数据源是 NPhase 实例。所以它没有 DeadClick 属性。因此,您可以使用Visual Studio中的Output
窗口进行检查。
我建议您可以这样做:
<DataTemplate x:Key="DeadLoadIDColumn">
<Button Content="{Binding Phases, Path=DeadLoadID}"
Command="{Binding Path=DataContext.DeadClick, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type l:NDataGrid}}}"/>
</DataTemplate>
我目前不明白如何编译 Content =“{Binding Phases,Path = DeadLoadID}”,因为我认为 Binding 子句的默认值是路径属性,您已指定它两次。
修改强> 在我得到小解决方案后,一切都变得清晰。 Here是修改后的解决方案。我在其中更改了所有内容 - 我已将 RelativeSource 添加到命令绑定中,如上所述,我为您的OptionsTab添加了MainWindow作为DataContext(您已在问题中指定了它,但未在项目中指定) )。就是这样 - 一切正常 - 调用命令getter,并在单击按钮时执行命令。