12

Is there any good way to bind a property to a const value in codebehind?

When I use ComboBox, I usually do this way in xaml and code behind:

XAML:

<ComboBox Name="cbBuz">
   <ComboBoxItem Content="foo" Uid="foo" IsSelected="true" />
   <ComboBoxItem Content="bar" Uid="bar" />
</ComboBox>

Codebehind:

ComboBoxItem item = cbBuz.GetSelectedItem();
switch (item.Uid)
{
    case "foo":  ... break;
    case "bar":  ... break;
}

The reason why I chose this way is following:

  • For localization purpose, Content string should not be used to determine which item is selected during saving and loading a last selected item.
  • For simplicity, XAML and code-behind should be connected internal identifier (In this case, Uid). So that, XAML and Code-behind can be maintained separately.

However, maintenance-wise, the internal identifier should be defined in one-place like this:

//IDs
public const string ID_foo = "foo";
public const string ID_bar = "bar";

...

//
switch (item.Uid)
{
    case ID_foo:  ... break;
    case ID_bar:  ... break;
}

The problem is seemingly property cannot be const value, so there's no way to bind ID_foo and ID_bar to Uid of ComboBoxItem like this:

//If ID_foo and ID_bar are properties, this will work.
<ComboBox Name="cbBuz">
   <ComboBoxItem Content="foo" Uid="{Binding ID_foo}" IsSelected="true" />
   <ComboBoxItem Content="bar" Uid="{Binding ID_bar}" />
</ComboBox>

So, I want to know how to solve this issue. Or, is there any better way to implement it. It would be nice, too.

Best,

Aki24x
  • 1,058
  • 1
  • 13
  • 28

2 Answers2

38

You would be better off using the StaticExtension, like so:

Uid="{x:Static local:YourClass.ID_foo}"

Where local is an xmlns alias for the C# namespace of your class. More information can be found here.

The problem with using Binding is you are adding a lot overhead for something that will never change. The binding will attempt to monitor your property. Also, there are known "leaks" with using a Binding with a non-dependency property on an object that don't implement INotifyPropertyChanged.

CodeNaked
  • 40,753
  • 6
  • 122
  • 148
  • Thanks a lot! This is exactly what I wanted! Also, the information related to leak and overhead is really useful. – Aki24x Mar 17 '11 at 02:23
  • 4
    Pro tip: when the constant is a number, make sure the types match. I tried with an int and tried to set a System.Windows.FrameworkElement.Height (a double) in XAML, and it gave me a XamlParseException: "'23' is not a valid value for property 'Height'." – Eric Eggers Jun 22 '18 at 16:15
  • Another important note is that the constant needs to be `internal` or `public`. Otherwise there is a XamlC error. The relationship of Xaml and Xaml.cs differs from other classes marked as `partial` (at least for Xamarin.Forms, assume for WPF / MAUI too). – this.myself Nov 17 '22 at 07:58
2

You need to make a property that returns the constant (defined in a const), ie:

private const string ID_Foo = "foo";
public string FooId
{
   get { return ID_Foo; }
}

Once this is in a property, it will be usable via binding.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Oh, that's right. Is there any way to make this shorter? I mean if it's C++, we can use #define to make macro, but we can't. I am wondering IValueConverter and Enum could make this shorter when adding new Uid to ComboBox, not in terms of a volume of whole code. – Aki24x Mar 16 '11 at 22:49
  • 1
    @Aki24x: You could potentially do this via an IValueConverter and specifying a value in XAML as a constant (not via binding), instead. That would allow a single IValueConverter to do a lookup somehow, but you'd need something for it to look up, ie: a name in a dictionary, or use an enum, or... – Reed Copsey Mar 16 '11 at 23:42