2

I would like to add an interaction trigger as in the xaml example below:

<ComboBox ...>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="DropDownClosed">
            <i:InvokeCommandAction Command="{Binding DataContext.DropDownCommand, RelativeSource={RelativeSource Findancestor, AncestorType = { x:Type Window}}}" CommandParameter="{Binding Path=.}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    ...
</ComboBox>

I tried this working code (until add Interaction.Trigger):

//ComboBox
FrameworkElementFactory combobox = new FrameworkElementFactory(typeof(ComboBox));
combobox.SetBinding(ComboBox.SelectedItemProperty, selectedItembinding);
combobox.SetBinding(ComboBox.ItemsSourceProperty, itemsourcebinding);
combobox.SetValue(ComboBox.DisplayMemberPathProperty, columnName.DisplayMemberPathName);
combobox.SetValue(ComboBox.StyleProperty, comboBoxStyle);
combobox.SetValue(ComboBox.ItemContainerStyleProperty, itemContainerStyle);

But I cannot bind the Interaction code to the ComboBox:

//Interaction.Triggers
InvokeCommandAction invokeCommandAction = new InvokeCommandAction { CommandParameter = "{Binding Path=.}" };
Binding binding = new Binding { Path = new PropertyPath("DataContext.DropDownCommand") };
BindingOperations.SetBinding(invokeCommandAction, InvokeCommandAction.CommandProperty, binding);

Microsoft.Xaml.Behaviors.EventTrigger eventTrigger = new Microsoft.Xaml.Behaviors.EventTrigger { EventName = "DropDownClosed" };
eventTrigger.Actions.Add(invokeCommandAction);

TriggerCollection triggers = Interaction.GetTriggers(combobox); <= this raises an error
triggers.Add(eventTrigger);

Whole Method Here is the whole method to understand how the parts of code are used:

private static DataGridTemplateColumn GetComboBoxUniqueColumn(ComboBoxUniqueColumn columnName)  
{
    DataGridTemplateColumn column = new DataGridTemplateColumn();
    column.IsReadOnly = true;
    column.Header = columnName.DisplayColumnName;
    column.Width = columnName.Width;
    column.MinWidth = GetMinWidth(columnName.Width);

    //Binding
    Binding selectedItembinding = new Binding();
    selectedItembinding.Path = new PropertyPath(columnName.SelectedItemPropertyName);
    selectedItembinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

    Binding itemsourcebinding = new Binding();
    itemsourcebinding.Path = new PropertyPath(string.Format("DataContext.{0}", columnName.ItemSourcePropertyName));
    itemsourcebinding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1);

    Binding isselectablebinding = new Binding();
    isselectablebinding.Path = new PropertyPath("IsSelectable");

    //Style
    Style comboBoxStyle = Application.Current.Resources["DataGridComboBox"] as Style;

    Style itemContainerStyle = new Style();
    itemContainerStyle.TargetType = typeof(ComboBoxItem);
    itemContainerStyle.BasedOn = Application.Current.Resources["DataGridComboBoxItemContainerStyle"] as Style;
    itemContainerStyle.Setters.Add(new Setter(ComboBoxItem.IsEnabledProperty, isselectablebinding));

    //ComboBox
    FrameworkElementFactory combobox = new FrameworkElementFactory(typeof(ComboBox));
    combobox.SetBinding(ComboBox.SelectedItemProperty, selectedItembinding);
    combobox.SetBinding(ComboBox.ItemsSourceProperty, itemsourcebinding);
    combobox.SetValue(ComboBox.DisplayMemberPathProperty, columnName.DisplayMemberPathName);
    combobox.SetValue(ComboBox.StyleProperty, comboBoxStyle);
    combobox.SetValue(ComboBox.ItemContainerStyleProperty, itemContainerStyle);

    //Interaction.Triggers
    //InvokeCommandAction invokeCommandAction = new InvokeCommandAction { CommandParameter = "{Binding Path=.}" };
    //Binding binding = new Binding { Path = new PropertyPath("DataContext.DropDownCommand") };
    //BindingOperations.SetBinding(invokeCommandAction, InvokeCommandAction.CommandProperty, binding);

    //Microsoft.Xaml.Behaviors.EventTrigger eventTrigger = new Microsoft.Xaml.Behaviors.EventTrigger { EventName = "DropDownClosed" };
    //eventTrigger.Actions.Add(invokeCommandAction);

    //TriggerCollection triggers = Interaction.GetTriggers(??);
    //triggers.Add(eventTrigger);
            
    //Set to DataTemplate
    var datatemplate = new DataTemplate();
    datatemplate.VisualTree = combobox;

    //Set to DataGridTemplateColumn
    column.CellTemplate = datatemplate;

    return column;
}

This code works well actually, I'm just wondering how to reproduce the xaml code programmatically.

Yannick
  • 194
  • 8
  • Do you want to do this process behind the code? If you want to do it code-behind, what's the point of it? – Ozgur Saklanmaz May 08 '23 at 21:00
  • It's a part of a behavior to manage DataGrid columns from the view model see: https://stackoverflow.com/questions/36737997/textwrapping-in-datagrid-with-itemsource-with-collection-of-expandoobjects – Yannick May 09 '23 at 08:30

1 Answers1

0

You can defer a trigger creation and put it for instance to the event handler for Loaded.

Add this to the method where DataTemplate being created:

combobox.AddHandler(ComboBox.LoadedEvent, new RoutedEventHandler(Cmb_Loaded));.

Triggers thus you can attach in the event handler, where you have access to the ComboBox:

private static void Cmb_Loaded(object sender, RoutedEventArgs e)
{
    if (sender is ComboBox cmb)
    {
        var invokeCommandAction = new InvokeCommandAction { CommandParameter = "{Binding Path=.}" };
        var binding = new Binding { Path = new PropertyPath("DataContext.DropDownCommand"), RelativeSource=new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Window), 1) };
        BindingOperations.SetBinding(invokeCommandAction, InvokeCommandAction.CommandProperty, binding);

        var eventTrigger = new Microsoft.Xaml.Behaviors.EventTrigger { EventName = "DropDownClosed" };
        eventTrigger.Actions.Add(invokeCommandAction);

        TriggerCollection triggers = Interaction.GetTriggers(cmb);
        triggers.Add(eventTrigger);
    }
}
Rekshino
  • 6,954
  • 2
  • 19
  • 44