Home > Enterprise >  Access auto generated buttons inside WPF Datagrid by their xNames
Access auto generated buttons inside WPF Datagrid by their xNames

Time:02-01

I have this DataGrid filled with products and there stocks and as well as an auto generated button per items, i want to call this auto generated button using there xNames so that when the stocks of a specific item became 0 i will simply disable it's button which is also auto generated, but my problem is i cannot call it.

I tried a lot such using FindNames in datagrid but still won't work\

<DataGrid.Columns>
                                        <DataGridTextColumn IsReadOnly="True" Binding="{Binding id}" Header="Product ID" Width="Auto"></DataGridTextColumn>
                                        <DataGridTextColumn ElementStyle="{StaticResource ProductNameCellMargin}" IsReadOnly="True" Binding="{Binding item_name}" Header="Product Name" Width="*"></DataGridTextColumn>
                                        <DataGridTextColumn ElementStyle="{StaticResource ProductNameCellMargin}" IsReadOnly="True" Binding="{Binding item_price}" Header="Price" Width="*"></DataGridTextColumn>
                                        <DataGridTextColumn ElementStyle="{StaticResource ProductNameCellMargin}" IsReadOnly="True" Binding="{Binding item_quantity}" Header="Quantity" Width="*"></DataGridTextColumn>
                                        <DataGridTemplateColumn IsReadOnly="True" HeaderStyle="{StaticResource CenterGridHeaderStyle}" Header="Remove" MinWidth="50" CanUserSort="False" CanUserResize="False">
                                            <DataGridTemplateColumn.CellTemplate>
                                                <DataTemplate>
                                                    <Button Background="Transparent" BorderBrush="Transparent" x:Name="select_item_btn" Padding="5, 2, 5, 2" Cursor="Hand" Click="remove_btn_Click">
                                                        <DockPanel>
                                                            <Image Height="18" Width="19" Source="img/Remove.png" />
                                                        </DockPanel>
                                                        <Button.Style>
                                                            <Style TargetType="Button">
                                                                <Setter Property="Background" Value="LightGray"/>
                                                                <Setter Property="Template">
                                                                    <Setter.Value>
                                                                        <ControlTemplate TargetType="{x:Type Button}">
                                                                            <Border Background="{TemplateBinding Background}">
                                                                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                                                            </Border>
                                                                        </ControlTemplate>
                                                                    </Setter.Value>
                                                                </Setter>
                                                                <Style.Triggers>
                                                                    <Trigger Property="IsMouseOver" Value="True">
                                                                        <Setter Property="Background" Value="LightGray"></Setter>
                                                                    </Trigger>
                                                                </Style.Triggers>
                                                            </Style>
                                                        </Button.Style>
                                                    </Button>
                                                </DataTemplate>
                                            </DataGridTemplateColumn.CellTemplate>
                                        </DataGridTemplateColumn>
                                    </DataGrid.Columns>

CodePudding user response:

You could use a DataTrigger to disable the Button based on the value of some source property, e.g.:

<Button Background="Transparent" BorderBrush="Transparent" x:Name="select_item_btn" 
        Padding="5, 2, 5, 2" Cursor="Hand" Click="remove_btn_Click">
    <DockPanel>
        <Image Height="18" Width="19" Source="img/Remove.png" />
    </DockPanel>
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="Background" Value="LightGray"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding item_quantity}" Value="0">
                    <Setter Property="IsEnabled" Value="False" />
                </DataTrigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="LightGray"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>

The above sample markup should disable the Button when the item_quantity property is 0.

CodePudding user response:

Rather than handling click events it is usual in wpf to use a command with a button. Bind the command property of the button to an icommand in the parent datacontext / viewmodel or the item viewmodel.

ICommand has CanExecute.

https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.icommand.canexecute?view=net-7.0#system-windows-input-icommand-canexecute(system-object)

If that returns false then the button will be disabled and not run.

https://learn.microsoft.com/en-us/answers/questions/433293/mvvm-relaycommand-icommand

The community toolkit mvvm makes defining commands pretty easy.

https://blogs.msmvps.com/bsonnino/2022/08/06/the-mvvm-pattern-revisited-with-the-mvvm-community-toolkit-8-0/

Here the last lambda expression is canexecute:

RemoveCommand = new RelayCommand(DoRemove, () => SelectedCustomer != null);

You would be checking stocks somehow instead of selectedcustomer, more like:

RemoveCommand = new RelayCommand(DoRemove, () => StockLevel > 0);

But, as the article illustrates, you can instead use an attribute

 [RelayCommand(CanExecute = "HasStock")]
 private void Remove()

I'm not sure what remove button does but you might want a command parameter for the row and the command in the parent viewmodel if you're removing a given row out the datagrid.

A RelayCommand is designed to receive a parameter to it's method.

A relativesource binding would allow you to bind from the button to the DataContext.RemoveCommand if necessary.

  • Related