This has been a long problem of mine, and even though there are a lot of solutions out there, none has seemed to work for me.
How do I make the DataGridComboBoxColumn
display as Combobox
when it is not focused?
I tried using DataGridTemplateColumn
and I've almost been successful in it except that when trying to identify the selected item in the Combobox
, the value returns back to previous data, and honestly made it a lot harder for me to work on this compared to just using DataGridComboBoxColumn
.
How can I do this without using DataGridTemplateColumn
?
The DataGrid
is found in a UserControl
which is dynamically added to the MainWindow.
<!-- This is my preferred way-->
<DataGridComboBoxColumn Header TagType x:Name="TagTypeCombo" SelectedValueBinding="{Binding TagType}"/>
<!--This is similar to all of solutions that I've seen-->
<DataGridTemplateColumn Header="Tag Type" x:Name="ComboTemplate">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="135" x:Name="Tagger" ItemsSource="{Binding tagType,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" SelectedItem="{Binding Tags}" SelectedValuePath="TagType"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
public int counter;
List<Tags> tags = new List<Tags>();
public event EventHandler SaveButtonClicked;
public List<string> tagType = new List<string>() { "Modbus Coil(0x)", "Discrete Input(1x)", "Input Register(3x)", "Holding Register(4x)" };
public ModbusCard2()
{
InitializeComponent();
}
public class Tags
{
public int TagAddress { get; set; }
public string TagType { get; set; }
public string TagID { get; set; }
}
private void DeleteButton_Click(object sender, RoutedEventArgs e) => ((WrapPanel)this.Parent).Children.Remove(this);
private void Tagger_Loaded(object sender, RoutedEventArgs e)
{
var cx = sender as ComboBox;
cx.ItemsSource = tagType;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 1; i <= counter; i++)
{
tags.Add(new Tags() { TagAddress = 0, TagID = $"M{i}", TagType = "Discrete Input(1x)" });
}
DevTags.ItemsSource = tags;
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
SaveButtonClicked?.Invoke(sender, e);
}
private void EditButton_Click(object sender, RoutedEventArgs e) => DevTags.IsReadOnly = false;
//For the SaveButtonClicked found in MainWindow
private void SaveButtonClicked(ModbusCard2 d)
{
foreach (var a in d.DevTags.Items.OfType<Tags>().ToList())
{
if (a.TagType == d.tagType[1])
{
a.TagID = $"M{DICount}";
DICount++;
}
if (a.TagType == d.tagType[2])
{
a.TagID = $"R{AICount}";
AICount++;
}
d.DevTags.Items.Refresh();
}
d.DevTags.IsReadOnly = true;
}
Try this with your ComboBox
that's currently inside your TemplateColumn
.
It adds logic in your binding to update your source trigger, while also removing your SelectedValuePath
tag. I'm assuming based on your lack of a DisplayMemberPath
tag that your ComboBox
ItemsSource
is a string collection. If this is the case the SelectedValuePath
can actually wreck your bindings (I have no idea why though).
<ComboBox Width="135" x:Name="Tagger" ItemsSource="{Binding tagType,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=UserControl}}" SelectedItem="{Binding Tags, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Let me know if you still have binding update issues after, and will go from here.