[英]WPF Button Command binding
我有一个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>
我以为这意味着Click事件将绑定到所需的OptionsTab.DataContext = MainWindow's
函数。但是,这不起作用(但是Content
起作用了)。 因此,我开始查找事物,并看到了另一个SO问题的答案 (Rachel的博客对我有很大帮助),据我了解,您无法将click事件{bind}到一个方法,但是必须将Command
属性绑定到ICommand
属性(使用助手RelayCommand
类),这RelayCommand
您带到所需的方法中。 所以我实现了,但是没用。 如果我将调试断点放在DeadClick
getter或OpenDeadLoadSelector()
并运行程序,则单击按钮不会触发任何操作,这意味着{Binding}不起作用。
我想知道这是否是我的误解,或者我只是在执行代码时做错了什么(随后删除了不相关的代码):
MainWindow.xaml
<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>
MainWindow.xaml.cs
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();
}
}
OptionsTab.xaml
<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.cs
public NOptionsTab(MainWindow w)
{
DataContext = w;
InitializeComponent();
PhaseGrid.ItemsSource = w.Phases;
}
当我们讨论它时(这可能是一个相关的问题),为什么{Binding Phases, Path=DeadLoadID}
在DataTemplate
上起作用(这就是为什么按钮显示为“ Select”的原因),但是如果我这样做了{Binding Phases, Path=Name}
,然后从构造函数中删除.ItemsSource
代码,什么都没有发生? PhaseGrid不应该继承其父级的(NOptionsTab / Grid) DataContext
吗? 甚至设置PhaseGrid.DataContext = w;
没有.ItemsSource
代码,什么也不会做。
编辑(27/04/14):
我认为了解NPhase
类本身的内容将很有用,所以这里是:
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;
}
}
编辑(29/04/14):
可以从此处( https://dl.dropboxusercontent.com/u/3087637/WPF.zip )下载简化的项目(摆脱不必要的所有内容)。
我认为存在一个问题,您没有为网格内的数据项正确指定数据源。
我认为您的按钮列的数据源是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子句的默认值是Path属性,并且已指定两次。
编辑我得到小的解决方案后,一切都变得清晰了。 这是修改后的解决方案。 我所做的所有更改-如上所述,我已将RelativeSource添加到命令绑定中,并且为OptionsTab添加了MainWindow作为DataContext(您在问题中指定了它,但未在项目中指定它)。 就这样-一切正常-调用命令getter,并在单击按钮时执行命令。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.