WPF按钮命令绑定

时间:2014-04-26 16:36:57

标签: c# wpf xaml binding icommand

我有一个MainWindow:Window类,它包含我程序中的所有数据。 MainWindow的.xaml只包含一个动态填充的空TabControl(在代码隐藏中)。

其中一个标签(OptionsTab)将.DataContext定义为MainWindow,授予其访问所有数据的权限。 OptionsTab有一个DataGrid,其中有一列填充了Buttons,如下所示:

enter image description here

DataGrid填充了DataGridTemplateColumns,其中DataTemplate在主<Grid.Resources>中定义。我想将此按钮绑定到MainWindow中的函数(而不是它所在的OptionsTab)。

创建OptionsTab后,.DataContextMainWindow设置为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

1 个答案:

答案 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,并在单击按钮时执行命令。