tags:

views:

7305

answers:

6

I'm VERY new to WPF, and still trying to wrap my head around binding in XAML.

I'd like to populate a combobox with the values of a string collection in my.settings. I can do it in code like this:

Me.ComboBox1.ItemsSource = My.Settings.MyCollectionOfStrings

...and it works.

How can I do this in my XAML? is it possible?

Thanks

+6  A: 

Yes, you can (and should for the most part) declare bindings in XAML, since that's one of the most powerful features in WPF.

In your case, to bind the ComboBox to one of your custom settings you would use the following XAML:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:p="clr-namespace:WpfApplication1.Properties"
    Title="Window1">
    <StackPanel>
        <ComboBox
            ItemsSource="{Binding Source={x:Static p:Settings.Default}, Path=MyCollectionOfStrings}" />
    </StackPanel>
</Window>

Notice the following aspects:

  • We declared an XML namespace with the prefix 'p' that points to the .NET namespace where the 'Settings' class lives in order to refer to it in XAML
  • We used the markup extension '{Binding}' in order to declare a binding in XAML
  • We used the markup extension 'Static' in order to indicate that we want to refer to a static ('shared' in VB) class member in XAML
Enrico Campidoglio
A: 

It is possible. In C#, I do it like this (for a simple bool):

IsExpanded="{Binding Source={StaticResource Settings}, Mode=TwoWay, Path=Default.ASettingValue}"

I define the static resource "Settings" in my App.xaml's Application.Resources thusly:

<!-- other namespaces removed for clarity -->
<Application xmlns:settings="clr-namespace:DefaultNamespace.Properties" >
 <Application.Resources>
  <ResourceDictionary>
   <settings:Settings x:Key="Settings" />
   <!--stuff removed-->
  </ResourceDictionary>
 </Application.Resources>
</Application>

Your path may be different; in C#, you access app settings in your application via

DefaultNamespace.Properties.Settings.Default.ASettingValue
Will
A: 

Well... I'm using VB, and I'm still not understanding something. I don't seem to have the application.properties item to bind to in VB. Thoughts?

B2Ben
Just change that to the namespace of your application.
Bob King
A: 

Got it!

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:p="clr-namespace:WpfApplication1"
    Title="Window1" Height="90" Width="462" Name="Window1">
    <Grid>
        <ComboBox ItemsSource="{Binding Source={x:Static p:Settings.Default}, Path=MyCollectionOfStrings}" />
    </Grid>
</Window>

Thank you all for helping me reach a great "Aha!" moment :-) ...hopefully after I spend some more time in WPF I'll understand why this works.

B2Ben
How about marking one the answers as "answered"? :)
Gustavo Cavalcanti
There may be a better answer here, but it's been two years since the issue was fresh in my mind and I rarely work with WPF now. so I'll mark my last post here as the answer.
B2Ben
+1  A: 

I have a simpler solution for doing that, using a custom markup extension. In your case it could be used like this :

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:WpfApplication1"
    Title="Window1" Height="90" Width="462" Name="Window1">
    <Grid>
        <ComboBox ItemsSource="{my:SettingBinding MyCollectionOfStrings}" />
    </Grid>
</Window>

You can find the C# code for this markup extension on my blog here : http://tomlev2.wordpress.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/

Thomas Levesque
A: 

You could also store the list as a delimited string in settings then use a converter.

<ComboBox ItemsSource="{Binding Default.ImportHistory,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,Converter={StaticResource StringToListConverter},ConverterParameter=|}" IsEditable="True">
/// <summary>
/// Converts a delimited set of strings to a list and back again. The parameter defines the delimiter
/// </summary>
public class StringToListConverter : IValueConverter {
 /// <summary>
 /// Takes a string, returns a list seperated by {parameter}
 /// </summary>
 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
     string serializedList = (value ?? string.Empty).ToString(),
            splitter = (parameter ?? string.Empty).ToString();
     if(serializedList.Trim().Length == 0) {
         return value;
     }
     return serializedList.Split(new[] { splitter }, StringSplitOptions.RemoveEmptyEntries);
 }
 /// <summary>
 /// Takes a list, returns a string seperated by {parameter}
 /// </summary>
 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
     var items = value as IEnumerable;
     var splitter = (parameter ?? string.Empty).ToString();
     if(value == null || items == null) {
         return value;
     }
     StringBuilder buffer = new StringBuilder();
     foreach(var itm in items) {
         buffer.Append(itm.ToString()).Append(splitter);
     }
     return buffer.ToString(0, splitter.Length > 0 ? buffer.Length - splitter.Length : buffer.Length);
 }
}

Then when a browse button is clicked, you can add to the list:

var items = Settings.Default.ImportHistory.Split('|');
if(!items.Contains(dlgOpen.FileNames[0])) {
 Settings.Default.ImportHistory += ("|" + dlgOpen.FileNames[0]);
}
cboFilename.SelectedValue = dlgOpen.FileNames[0];
Settings.Default.Save();
Echilon