繁体   English   中英

2 个控件中托管的按钮的绑定问题

[英]Binding issue with button hosted in 2 controls

嗨,我知道这是很多代码,但我希望有人可以帮助或指出正确的方向,即使在命令和任务上使用断点,我的导出到 csv 命令也不会触发,所以我认为找不到在某处的数据上下文中,其他所有工作都可以填充数据,编辑按钮可以工作。 所以我有 2 个UserControlTitleControlBillOfMaterialsControl ,我在标题控件中托管了一些按钮,这些按钮托管在物料清单控件中,看来我的按钮不适用于托管在另一个控件中。

我在 output window 中收到此错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'ExportButtonCommand' property not found on 'object' ''TitleControl' (Name='')'. BindingExpression:Path=ExportButtonCommand; DataItem='TitleControl' (Name=''); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')

很感谢任何形式的帮助。

BillOfMaterials.xaml 控制

<UserControl x:Class="Bright_Instruments.Controls.BillOfMaterialsControl"
         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:local="clr-namespace:Bright_Instruments.Controls"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800" xmlns:controls="clr-namespace:Bright_Instruments.Controls"
         xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
         xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls">

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>

    <controls:TitleControl Grid.Column="0" Badge="{Binding Badge, RelativeSource={RelativeSource AncestorType=UserControl}}" Grid.Row="0" Margin="5" Text="PARTS LIST" Icon="{iconPacks:PicolIcons Kind=ListNumbered}">
        <controls:TitleControl.TitleContent>
            <StackPanel Margin="0" HorizontalAlignment="Right" Orientation="Horizontal">
                <Button ToolTip="Print parts list" Margin="5" HorizontalAlignment="Right" Style="{DynamicResource MahApps.Styles.Button.Chromeless}">
                    <Button.Content>
                        <iconPacks:PackIconEntypo Kind="Print"/>
                    </Button.Content>
                </Button>

                <Button Margin="5" 
                        Command="{Binding ExportButtonCommand, RelativeSource={RelativeSource AncestorType=UserControl}, UpdateSourceTrigger=PropertyChanged}" ToolTip="Export parts list to .csv" HorizontalAlignment="Right" Style="{DynamicResource MahApps.Styles.Button.Chromeless}">
                    <Button.Content>
                        <iconPacks:PackIconFontAwesome Kind="FileCsvSolid"/>
                    </Button.Content>
                </Button>

                <Button Margin="5" ToolTip="Export parts list to .pdf" HorizontalAlignment="Right" Style="{DynamicResource MahApps.Styles.Button.Chromeless}">
                    <Button.Content>
                        <iconPacks:PackIconFontAwesome Kind="FilePdfSolid"/>
                    </Button.Content>
                </Button>
            </StackPanel>
        </controls:TitleControl.TitleContent>
    </controls:TitleControl>

    <StackPanel Orientation="Horizontal" Grid.Column="1">
        <Button Margin="0, 5, 5, 5" 
            Command="{Binding EditButtonCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" 
            Style="{DynamicResource MahApps.Styles.Button.Flat}" 
            Content="EDIT"/>
    </StackPanel>

    <DataGrid Grid.Row="1" AutoGenerateColumns="False" Grid.Column="0" Grid.ColumnSpan="2" 
              ItemsSource="{Binding BillOfMaterials, RelativeSource={RelativeSource AncestorType=UserControl}, UpdateSourceTrigger=PropertyChanged}" Margin="5" IsReadOnly="True" SelectionMode="Single">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=ChildItem.PartNumber}" Width="Auto">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconFontAwesome Kind="WrenchSolid" Margin="5" />
                        <TextBlock Margin="5" Text="PART NUMBER"/>
                    </StackPanel>
                </DataGridTextColumn.Header>
            </DataGridTextColumn>

            <DataGridTextColumn Binding="{Binding Path=ChildItem.Description}" Width="*">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconMaterialDesign Kind="Description" Margin="5" />
                        <TextBlock Margin="5" Text="DESCRIPTION"/>
                    </StackPanel>
                </DataGridTextColumn.Header>

                <DataGridTextColumn.ElementStyle>
                    <Style>
                        <Setter Property="TextBlock.TextWrapping" Value="Wrap" />
                        <Setter Property="TextBlock.TextAlignment" Value="Left"/>
                    </Style>
                </DataGridTextColumn.ElementStyle>
            </DataGridTextColumn>

            <DataGridTextColumn Binding="{Binding Path=ChildItem.Location}" Width="Auto">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconMaterialDesign Kind="LocationOn" Margin="5" />
                        <TextBlock Margin="5" Text="LOCATION"/>
                    </StackPanel>
                </DataGridTextColumn.Header>
            </DataGridTextColumn>

            <DataGridTextColumn Binding="{Binding Path=ChildItem.Quantity}" Width="Auto">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconMaterial Kind="Numeric" Margin="5" />
                        <TextBlock Margin="5" Text="QUANTITY IN STOCK"/>
                    </StackPanel>
                </DataGridTextColumn.Header>
            </DataGridTextColumn>

            <DataGridTextColumn Width="Auto" Binding="{Binding Path=Quantity}">
                <DataGridTextColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconMaterial Kind="Numeric" Margin="5" />
                        <TextBlock Margin="5" Text="QUANTITY REQ"/>
                    </StackPanel>
                </DataGridTextColumn.Header>
            </DataGridTextColumn>

            <DataGridTemplateColumn Width="Auto">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Margin="0" Style="{DynamicResource MahApps.Styles.Button.Flat}" 
                                CommandParameter="{Binding }"
                                Command="{Binding ViewButtonCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" Content="VIEW"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>

                <DataGridTemplateColumn.Header>
                    <StackPanel Orientation="Horizontal">
                        <iconPacks:PackIconTypicons Margin="5" Kind="Eye"/>
                        <TextBlock Text="VIEW" Margin="5"/>
                    </StackPanel>
                </DataGridTemplateColumn.Header>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
    </UserControl>

BillOfMaterials.cs 控件

public partial class BillOfMaterialsControl : UserControl
{
    public BillOfMaterialsControl()
    {
        InitializeComponent();
    }

    public string Badge
    {
        get { return (string)this.GetValue(BadgeProperty); }
        set { SetValue(BadgeProperty, value); }
    }

    public static readonly DependencyProperty BadgeProperty = DependencyProperty.Register(
      "Badge", typeof(string), typeof(BillOfMaterialsControl), new PropertyMetadata(string.Empty));

    public ICommand ViewButtonCommand
    {
        get { return (ICommand)GetValue(ViewButtonCommandProperty); }
        set { SetValue(ViewButtonCommandProperty, value); }
    }
    public static readonly DependencyProperty ViewButtonCommandProperty = DependencyProperty.Register(
      "ViewButtonCommand", typeof(ICommand), typeof(BillOfMaterialsControl), new UIPropertyMetadata(null));

    public ICommand ExportButtonCommand
    {
        get { return (ICommand)GetValue(ExoportButtonCommandProperty); }
        set { SetValue(ExoportButtonCommandProperty, value); }
    }
    public static readonly DependencyProperty ExoportButtonCommandProperty = DependencyProperty.Register(
      "ExportButtonCommand", typeof(ICommand), typeof(BillOfMaterialsControl), new UIPropertyMetadata(null));


    public ICommand EditButtonCommand
    {
        get { return (ICommand)GetValue(EditButtonCommandProperty); }
        set { SetValue(EditButtonCommandProperty, value); }
    }
    public static readonly DependencyProperty EditButtonCommandProperty = DependencyProperty.Register(
      "EditButtonCommand", typeof(ICommand), typeof(BillOfMaterialsControl), new UIPropertyMetadata(null));

    public List<BillOfMaterial> BillOfMaterials
    {
        get { return (List<BillOfMaterial>)this.GetValue(BillOfMaterialsProperty); }
        set { SetValue(BillOfMaterialsProperty, value); }
    }

    public static readonly DependencyProperty BillOfMaterialsProperty = DependencyProperty.Register(
      "BillOfMaterials", typeof(List<BillOfMaterial>), typeof(BillOfMaterialsControl), new PropertyMetadata(null));
}

TitleControl.xaml 控制

<UserControl x:Class="Bright_Instruments.Controls.TitleControl"
         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:local="clr-namespace:Bright_Instruments.Controls"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800"
         DataContext="{Binding RelativeSource={RelativeSource Self}}"
         xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls">

<Grid Background="{DynamicResource MahApps.Brushes.Accent}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
        <ContentPresenter Margin="5" Content="{Binding Icon}" 
                          TextBlock.Foreground="{DynamicResource MahApps.Brushes.IdealForeground}" />
        <TextBlock 
            Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" 
            FontSize="12" VerticalAlignment="Center" 
            HorizontalAlignment="Left" Background="Transparent" 
            Foreground="{DynamicResource MahApps.Brushes.IdealForeground}" 
            Padding="5"/>

        <Controls:Badged BadgePlacementMode="TopRight" Margin="10, 0, 0, 0" Badge="{Binding Badge}">
            <Controls:Badged.Style>
                <Style TargetType="Controls:Badged">
                    <Style.Triggers>
                        <Trigger Property="Badge" Value="">
                            <Setter Property="Visibility" Value="Collapsed" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Controls:Badged.Style>
        </Controls:Badged>
    </StackPanel>

    <ContentPresenter Content="{Binding TitleContent, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Grid.Row="0"/>

    <Rectangle Height="2" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Fill="{DynamicResource MahApps.Brushes.AccentBase}">

    </Rectangle>
</Grid>
    </UserControl>

TitleControl.cs 控件

public partial class TitleControl : UserControl
{
    public TitleControl()
    {
        InitializeComponent();
    }

    public string Text
    {
        get { return (string)this.GetValue(TextProperty); }
        set { this.SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
      "Text", typeof(string), typeof(TitleControl), new PropertyMetadata(string.Empty));

    public string Badge
    {
        get { return (string)this.GetValue(BadgeProperty); }
        set { this.SetValue(BadgeProperty, value); }
    }

    public static readonly DependencyProperty BadgeProperty = DependencyProperty.Register(
      "Badge", typeof(string), typeof(TitleControl), new PropertyMetadata(string.Empty));

    public PackIconBase Icon
    {
        get { return (PackIconBase)this.GetValue(IconProperty); }
        set { this.SetValue(IconProperty, value); }
    }

    public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
      "Icon", typeof(PackIconBase), typeof(TitleControl), new PropertyMetadata(null));

    public object TitleContent
    {
        get { return (object)GetValue(TitleContentProperty); }
        set { SetValue(TitleContentProperty, value); }
    }
    public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register(
      "TitleContent", typeof(object), typeof(TitleControl), new UIPropertyMetadata(null));
}

我对托管物料清单控制的看法

<controls:BillOfMaterialsControl
            EditButtonCommand="{Binding EditPartsListCommand}"
            Badge="{Binding PartsListCount}"
            ViewButtonCommand="{Binding ViewPartsListItemCommand}"
            ExportButtonCommand="{Binding ExportPartsListToCsvCommand, UpdateSourceTrigger=PropertyChanged}"
            BillOfMaterials="{Binding BillOfMaterials, UpdateSourceTrigger=PropertyChanged}"/>

视图视图模型

public ICommand ExportPartsListToCsvCommand => new AsyncRelayCommand(ExportPartsListToCsv);

public async Task ExportPartsListToCsv()
{
    
    var saveFileDialog = new SaveFileDialog();

    var filter = $"CSV (*.csv) | *.csv";

    saveFileDialog.Filter = filter;
    saveFileDialog.DefaultExt = ".csv";
    saveFileDialog.FileName = "Inventory.csv";
    if (saveFileDialog.ShowDialog() == true)
    {
        try
        {
            await CsvService.Write<BillOfMaterial>(saveFileDialog.FileName, BillOfMaterials);
        }
        catch (Exception ex)
        {
            SentrySdk.CaptureException(ex);
        }
    }
}

BillOfMaterialsControl使用TitleControl控件,该控件又包含一个将ExportButtonCommand (它是BillOfMaterialsControl中的属性)绑定为命令的Button 在这里,您使用其中具有祖先类型UserControl的相对源绑定。

Command="{Binding ExportButtonCommand, RelativeSource={RelativeSource AncestorType=UserControl}, UpdateSourceTrigger=PropertyChanged}"

想象与此类似的视觉树(仅包含其中的基本部分)。

  • BillOfMaterialsControl
    • TitleControl
      • Button

相对源绑定将向上搜索可视化树以找到UserControl类型的控件。 您的两个控件都派生自UserControl并且找到的第一个控件是TitleControl ,但是此控件不包含名为ExportButtonCommand的属性,这就是您遇到的绑定失败。

System.Windows.Data Error: 40 : BindingExpression path error: 'ExportButtonCommand' property not found on 'object' ''TitleControl' (Name='')'. BindingExpression:Path=ExportButtonCommand; DataItem='TitleControl' (Name=''); target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')

您可以通过其中一种方式解决此问题。

  • 修改绑定以使用控件BillOfMaterialsControl的具体类型作为祖先类型。 这样TitleControl不匹配。

     Command="{Binding ExportButtonCommand, RelativeSource={RelativeSource AncestorType=local:BillOfMaterialsControl}, UpdateSourceTrigger=PropertyChanged}"
  • 指定合适的AncestorLevel以跳过搜索过程中的控件。

     Command="{Binding ExportButtonCommand, RelativeSource={RelativeSource AncestorType=UserControl, AncestorLevel=2}, UpdateSourceTrigger=PropertyChanged}"

    2应该有效(如果没有,请调整它)。 来自AncestorLevel文档

    在 FindAncestor 模式下获取或设置要查找的祖先级别。 使用 1 表示离绑定目标元素最近的那个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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