繁体   English   中英

WPF按钮命令绑定

[英]WPF Button Command binding

我有一个MainWindow:Window类,该类保存程序中的所有数据。 MainWindow的.xaml仅包含一个空的TabControl,该控件动态填充(在后面的代码中)。

选项卡之一( OptionsTab )的.DataContext定义为MainWindow ,授予它对所有数据的访问权限。 OptionsTab有一个DataGrid ,其中有一个用Buttons填充的列,如下所示:

在此处输入图片说明

DataGridDataGridTemplateColumns填充,其中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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM