I keep going round and round with this issue with GitHub Copilot and have pretty much had the same experience with Gemini and ChatGPT, all giving me the same stuff I've already tried and going in circles with suggestions that for the most part just don't work.
In C#/WPF, I have an enum, an object containing a key from the enum and an associated value, and a KeyedCollection of these objects. e.g.
public enum MyEnum
{
Key1,
Key2,
Key3
}
public class MyObject : ObservableObjectBase
{
public MyEnum Key { get; set; }
public string Value { get; set; } // Actual implementation generates change event
}
public class MyCollection : KeyedCollection<MyEnum, MyObject>
{
protected override MyEnum GetKeyForItem(MyObject item)
{
return item.Key;
}
}
I need to bind the text of a textbox (or any component) to someCollection[key].Value using a static value from the enum. The someCollection will be a property of the window that contains the control, so is accessible from the DataContext. This seems like it SHOULD Be as easy as
<TextBox Text="{Binding Path=someCollection[namespace:MyEnum.Key2].Value, Mode=TwoWay}" />
and this is one of the approaches every AI has suggested, but it gives a "No DataContext found for Binding" message in the VS IDE, and of course the binding doesn't work. The someCollection IS visible from the context and works for other components that are accessing it (such as below), as is the enum key that I want to use. One thing to note here is that the enum and MyCollection/MyObject code are all in a separate class library, but that shouldn't matter. And again, I can access those same pieces fine from the converter XAML below.
If I use a converter to extract the object (as commonly proposed by the AIs), I don't know how to then bind the control to object.Value rather than just object. The AIs will keep proposing that, but it won't work just returning a MyObject from the converter.
I was able to use a converter that just returns Value and gets/sets the value in the referenced object inside the Convert/ConvertBack functions.
<TextBox Text="{Binding someCollection, Converter={StaticResource CollectionToValueConverter}, ConverterParameter={x:Static namespace:MyEnum.Key2}}" />
However, in that scenario I lose the changed events from the object, presumably because the control isn't bound directly to the object. I don't want to make the collection propagate a changed event because that would refresh every single value whenever one is updated.
I've also tried AI suggested MultiBinding and nested binding approaches that never work. It does seem like it should be possible to do some sort of nested binding using the object converter that would look something like this:
<TextBox Text="{Binding Path=Value, DataContext={Binding someCollection, Converter={StaticResource CollectionToObjectConverter}, ConverterParameter={x:Static namespace:MyEnum.Key2}}}" />
Thanks for any suggestions. This seems like this should be a very easy and common thing to want to do, but it's feeling more and more like one of the many "You can't get there from here!" items I run into in C# and WPF.
Thanks,
Beo
The someCollection will be a property of the window that contains the control, so is accessible from the DataContext.
This is only true if you actually set the DataContext, i.e. like
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public MyCollection SomeCollection { get; } =
[
new MyObject { Key = MyEnum.Key1, Value = "Value 1" },
new MyObject { Key = MyEnum.Key2, Value = "Value 2" },
new MyObject { Key = MyEnum.Key3, Value = "Value 3" }
];
}
In the Binding expresssion, you would use the string representation Key2
of the enum value. Setting the Binding Mode
is redundant.
<TextBox Text="{Binding Path=SomeCollection[Key2].Value}" />
As mentioned in the Remarks on Binding.Path
, you could also explicitly specify the type of the indexer parameter, i.e.
<TextBox Text="{Binding Path=SomeCollection[(namespace:MyEnum)Key2].Value}" />