Binding to a list of FontWeight and FontStyle values - wpf

I am trying to bind to the list of defined FontWeights and FontStyles in WPF.
I was hoping to use the same technique used in this thread about Displaying the list of system fonts; however, I cannot documentation on the get_systemFontFaimlies method for Fonts structure and likewise I cannot find documentation for the FontWeights and FontStyles either.
Thank you for your help.
Edit:
While the response that #ethicallogics provided was helpful, and it is probably more flexible than my solution, I just simply declared arrays in my XAML and chose which FontWeight and FontStyle options I wanted to provide to the end user.
I also found documentation that I couldn't find yesterday for the SystemFonts.get_systemFontFaimlies method here. It is a shame but it appears that the FontWeights and FontStyles structures do not have anything like the get method that the SystemFonts structure has which is why I had to explicitly define arrays with the items that I wanted to provide to the end user.
Here is my XAML for the arrays I defined:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:media="clr-namespace:System.Windows.Media;assembly=PresentationCore"
xmlns:win="clr-namespace:System.Windows;assembly=PresentationCore"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ObjectDataProvider x:Key="FontFamilyOptions" ObjectType="{x:Type media:Fonts}" MethodName="get_SystemFontFamilies"/>
<x:Array x:Key="FontWeightOptions" Type="win:FontWeight">
<win:FontWeight>Normal</win:FontWeight>
<win:FontWeight>Bold</win:FontWeight>
<win:FontWeight>ExtraBold</win:FontWeight>
</x:Array>
<x:Array x:Key="FontStyleOptions" Type="win:FontStyle">
<win:FontStyle>Normal</win:FontStyle>
<win:FontStyle>Italic</win:FontStyle>
<win:FontStyle>Oblique</win:FontStyle>
</x:Array>
</ResourceDictionary>

Create a FontWrapper class like
public class FontsWrapper
{
static ICollection<FontWeight> fontWeights;
static ICollection<FontStyle> fontStyles;
static ICollection<FontFamily> fontFamilies;
public static ICollection<FontStyle> GetFontStyles()
{
return fontStyles ?? (fontStyles = new List<FontStyle>() { System.Windows.FontStyles.Italic, System.Windows.FontStyles.Normal, System.Windows.FontStyles.Oblique });//TODO:Get by reflection
}
public static ICollection<FontFamily> GetFontFamilies()
{
return fontFamilies ?? (fontFamilies = Fonts.SystemFontFamilies);
}
public static ICollection<FontWeight> GetFontWeights()
{
if (fontWeights == null)
fontWeights = new List<FontWeight>();
else
return fontWeights;
var type = typeof(FontWeights);
foreach (var p in type.GetProperties().Where(s => s.PropertyType == typeof(FontWeight)))
{
fontWeights.Add((FontWeight)p.GetValue(null, null));
}
return fontWeights;
}
public static ICollection<FontWeight> FontWeights
{
get { return fontWeights ?? (fontWeights = GetFontWeights()); }
}
public static ICollection<FontStyle> FontStyles
{
get { return fontStyles ?? (fontStyles = GetFontStyles()); }
}
public static ICollection<FontFamily> FontFamilies
{
get { return fontFamilies ?? (fontFamilies = GetFontFamilies()); }
}
}
xaml
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="fontFamiliesKey" ObjectType="{x:Type local:FontsWrapper}" MethodName="GetFontFamilies"/>
<ObjectDataProvider x:Key="fontWeightsKey" ObjectType="{x:Type local:FontsWrapper}" MethodName="GetFontStyles"/>
<ObjectDataProvider x:Key="fontStylesKey" ObjectType="{x:Type local:FontsWrapper}" MethodName="GetFontWeights"/>
</Window.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding Source={StaticResource fontFamiliesKey}}"></ComboBox>
<ComboBox ItemsSource="{Binding Source={StaticResource fontWeightsKey}}"></ComboBox>
<ComboBox ItemsSource="{Binding Source={StaticResource fontStylesKey}}"></ComboBox>
<!-- or Bind the Lists of wrapper class Directly -->
<ComboBox ItemsSource="{Binding Source={x:Static local:FontsWrapper.FontFamilies}}"></ComboBox>
<ComboBox ItemsSource="{Binding Source={x:Static local:FontsWrapper.FontStyles}}"></ComboBox>
<ComboBox ItemsSource="{Binding Source={x:Static local:FontsWrapper.FontWeights}}"></ComboBox>
</StackPanel>
I hope this will help.

In the end I just declared arrays as resources (with the options that I wanted to provide to the end user) in my XAML like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:media="clr-namespace:System.Windows.Media;assembly=PresentationCore"
xmlns:win="clr-namespace:System.Windows;assembly=PresentationCore"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ObjectDataProvider x:Key="FontFamilyOptions" ObjectType="{x:Type media:Fonts}" MethodName="get_SystemFontFamilies"/>
<x:Array x:Key="FontWeightOptions" Type="win:FontWeight">
<win:FontWeight>Normal</win:FontWeight>
<win:FontWeight>Bold</win:FontWeight>
<win:FontWeight>ExtraBold</win:FontWeight>
</x:Array>
<x:Array x:Key="FontStyleOptions" Type="win:FontStyle">
<win:FontStyle>Normal</win:FontStyle>
<win:FontStyle>Italic</win:FontStyle>
<win:FontStyle>Oblique</win:FontStyle>
</x:Array>
</ResourceDictionary>
And I used these as the item sources for my combo boxes like this:
<ComboBox ItemsSource="{Binding Source={StaticResource FontFamilyOptions}}" />
<ComboBox ItemsSource="{Binding Source={StaticResource FontWeightOptions}}" />
<ComboBox ItemsSource="{Binding Source={StaticResource FontStyleOptions}}" />

Related

Binding DataGridComboBoxColumn to enum value

I'm trying to bind an enum value to DataGridComboBoxColumn, but it does not work. In my case i want to bind the enum CamSegmentType to the DataGridComboBoxColumn. It seems that the enum eCamType could not be found. I don't know what's wrong.
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="825">
<Window.Resources>
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="GetEnumValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:eCamType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<Grid>
<DataGrid Name="dgCamSegements" AutoGenerateColumns="False" Margin="10,180,10,10">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Value" ItemsSource="{Binding Source={StaticResource GetEnumValues}}" SelectedValueBinding="{Binding CamSegmentType}" />
<DataGridTextColumn Header="Leitwert" Binding="{Binding MasterPosStart}" />
<DataGridTextColumn Header="Folgewert" Binding="{Binding SlavePosStart}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Code:
namespace WpfApp1
{
public partial class MainWindow : Window
{
public enum eCamType { Gerade, Polynom, };
public class CamSegment
{
public eCamType CamSegmentType { get; set; }
public double MasterPosStart { get; set; }
public double SlavePosStart { get; set; }
}
public MainWindow()
{
InitializeComponent();
...
Can anyone help me?
Add in Your Code:
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged in
SelectedValueBinding DataGridComboBoxColumn

Get value in app.config

I have the Key in app.config:
<appSettings>
<add key="SourceWindow" value="C:\Windows" />
</appSettings>
And in MainWindow.xaml have:
<ObjectDataProvider x:Key="keyFiles" MethodName="GetFiles" ObjectType="{x:Type io:Directory}">
<ObjectDataProvider.MethodParameters>
<sys:String> GET VALUE IN APP.CONFIG </sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
How i can get value in app.config -> <add key="SourceWindow" value="C:\Windows" /> and set this value in <sys:String> VALUE </sys:String>
by xaml?
Any suggestion?
To solve your issue, you can write your own MarkupExtension.
I prepared a short sample code for you. First of all let's see the MarkupExtension class that retrive the app.Config's appSettings:
namespace WpfApplication1
{
public class AppSettingsExtension : MarkupExtension
{
private string key;
public AppSettingsExtension()
{
}
public AppSettingsExtension(string key)
{
Key = key;
}
public string Key
{
get
{
return key;
}
set
{
key = value;
}
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ConfigurationManager.AppSettings[Key];
}
}
}
Now it is possible to use the AppSettingsExtension in a XAML (not inside a <sys:String /> node, since it already returns a string object):
<Window x:Class="WpfApplication1.MainWindow" Name="win"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:io="clr-namespace:System.IO;assembly=mscorlib"
Title="MainWindow" Height="350" Width="400">
<Window.Resources>
<local:AppSettings Key="SourceWindow" x:Key="str" />
<ObjectDataProvider x:Key="keyFiles" MethodName="GetFiles" ObjectType="{x:Type io:Directory}">
<ObjectDataProvider.MethodParameters>
<local:AppSettings Key="SourceWindow" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<StackPanel>
<Label Content="{StaticResource str}" Margin="4" />
<ItemsControl ItemsSource="{Binding Source={StaticResource keyFiles}}" />
</StackPanel>
</Window>
I hope my sample can help you.

Bind to result of static class' method

I have the following:
namespace Foo {
public static class Bar {
public static int Fubar() {
return 100;
}
}
}
Now I'm in xaml. I want to use that method to set the height of my rectangle.
<Rectangle Height="{Binding Source=???}">
You need an ObjectDataProvider to bind to a method.
Example (adjust to your NameSpace / Class / Method):
<Window x:Class="SerialPortBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ports="clr-namespace:System.IO.Ports;assembly=System"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<ObjectDataProvider ObjectType="{x:Type ports:SerialPort}"
MethodName="GetPortNames" x:Key="portNames"/>
</Window.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource portNames}}"/>
</Window>
The assembly portion of the xmnls at the top may not be needed; ignore it if it does not come up in CodeSense.
Try something like this:-
{Binding Source={x:Static classnamespace:Bar}, Path=Fubar}

Bindings inside CompositeCollection

I want to create a TabControl with a number of "static" TabItems (explicitly typed in XAML) and a number of dynamically added TabItems. To achieve this I tried to use a CompositeCollection as the TabControl.ItemSource.
Sample code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
>
<Window.Resources>
<x:Array x:Key="SomeTexts" x:Type="sys:String">
<sys:String>Text1</sys:String>
<sys:String>Text2</sys:String>
</x:Array>
</Window.Resources>
<TabControl>
<TabControl.ItemsSource>
<CompositeCollection>
<TabItem Header="Test">
<StackPanel>
<TextBlock x:Name="MyText" Text="Blah" />
<TextBlock Text="{Binding Text, ElementName=MyText}" />
</StackPanel>
</TabItem>
<CollectionContainer Collection="{StaticResource SomeTexts}" />
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
</Window>
This example has one fixed tab item and three "dynamic" tab items (note that 'SomeTexts' is a fixed array here just to ease the example; in the real code it will be a dynamic collection).
The example works except for the 'ElementName' binding, which does not work. I suppose this is because the CompositeCollection is not a Freezable (see also Why is CompositeCollection not Freezable?).
Does anyone has a solution?
I had a similar scenario. To solve this I found the following article.
This post explains how to create a freezable proxy object that you can set your data context to. You then add this proxy as a resource that can be referenced as a static resource. See the following:
public class BindingProxy : Freezable
{
public static DependencyProperty DataContextProperty = DependencyProperty.Register(
"DataContext", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
public object DataContext
{
get { return GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
}
This can then be used in your xaml like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:y="clr-namespace:Namespace.Of.BindingProxy"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
>
<Window.Resources>
<x:Array x:Key="SomeTexts" x:Type="sys:String">
<sys:String>Text1</sys:String>
<sys:String>Text2</sys:String>
</x:Array>
<y:BindingProxy x:Key="Proxy" DataContext="{Binding}" />
</Window.Resources>
<TabControl>
<TabControl.ItemsSource>
<CompositeCollection>
<TabItem Header="Test">
<StackPanel>
<TextBlock x:Name="MyText" Text="Blah" />
<TextBlock Text="{Binding DataContext.SomeProperty, Source={StaticResource Proxy}}" />
</StackPanel>
</TabItem>
<CollectionContainer Collection="{StaticResource SomeTexts}" />
</CompositeCollection>
</TabControl.ItemsSource>
</TabControl>
</Window>

WPF -- Anyone know why I can't get this binding to reference?

<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3"
DataContext="{Binding Mode=OneWay, Source={StaticResource local:oPatients}}">
I'm getting StaticResource reference 'local:oPatients' was not found.
Here is the codebehind:
public partial class MainWindow : Window
{
ListBox _activeListBox;
clsPatients oPatients;
public MainWindow()
{
oPatients = new clsPatients(true);
...
To be able to address the object as a StaticResource, it needs to be in a resource dictionary. However, since you're creating the object in MainWindow's constructor, you can set the DataContext in the code-behind like so.
oPatients = new clsPatients(true);
stkWaitingPatients.DataContext = oPatients;
And then change the Binding to this:
{Binding Mode=OneWay}
This is an ok practice if you're not going to be changing the DataContext again, otherwise you'd want a more flexible solution.
Edit: You mentioned ObjectDataProvider in your comment. Here's how you'd do that. First, add an xmlns:sys to the Window for the System namespace (I'm assuming you already have one for xmlns:local):
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Then you can add an ObjectDataProvider to your resource dictionary like this:
<Window.Resources>
<ObjectDataProvider
x:Key="bindingPatients"
ObjectType="{x:Type local:clsPatients}">
<ObjectDataProvider.ConstructorParameters>
<sys:Boolean>True</sys:Boolean>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
</Window.Resources>
And refer to it in a Binding with the StaticResource markup like this, using the same string we specified in the x:Key attached property we gave it in the dictionary:
{Binding Source={StaticResouce bindingPatients}, Mode=OneWay}
Edit 2: Ok, you posted more code in your answer, and now I know why it's throwing an exception during the constructor. You're attempting to do this...
lstWaitingPatients.DataContext = oPatients;
... but lstWaitingPatients doesn't actually exist until after this.InitializeComponent() finishes. InitializeComponent() loads the XAML and does a bunch of other things. Unless you really need to do something before all of that, put custom startup code after the call to InitalizeComponent() or in an event handler for Window's Loaded event.
The following sets the ItemsSource in Code Behind and correctly handles the DataBinding:
public partial class MainWindow : Window
{
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
//assuming oPatients implements IEnumerable
this.lstWaitingPatients.ItemsSource = oPatients;
And the XAML:
<ListBox x:Name="lstWaitingPatients"
IsSynchronizedWithCurrentItem="true"
ItemTemplate="{StaticResource WaitingPatientsItemTemplate}"
FontSize="21.333" Height="423.291"
ScrollViewer.VerticalScrollBarVisibility="Visible"
GotFocus="lstWaitingPatients_GotFocus"
/>
Now, I can't get this to work...I get a general Windows startup error.
Here is the codebehind with the Initializer and the class being instantiated:
public partial class MainWindow : Window
{
ListBox _activeListBox;
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
lstWaitingPatients.DataContext = oPatients;
this.InitializeComponent();
Here's the top of my XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Orista_Charting"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
x:Class="Orista_Charting.MainWindow"
x:Name="windowMain"
Title="Orista Chart"
Width="1024" Height="768" Topmost="True" WindowStartupLocation="CenterScreen" Activated="MainWindow_Activated" >
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/ButtonStyles.xaml"/>
<ResourceDictionary Source="Resources/OtherResources.xaml"/>
<ResourceDictionary Source="Resources/TextBlockStyles.xaml"/>
<ResourceDictionary Source="Resources/Converters.xaml"/>
</ResourceDictionary.MergedDictionaries>
Here's the pertinent XAML, as you see, I went ahead and moved the DataContext down to the ListBox from the StackPanel. This doesn't run, but it does render in Design View (however, with no data present in the ListBox):
<!-- Waiting Patients List -->
<Border BorderThickness="1,1,1,1" BorderBrush="#FF000000" Padding="10,10,10,10"
CornerRadius="10,10,10,10" Background="#FFFFFFFF" Margin="15.245,187.043,0,41.957" HorizontalAlignment="Left" >
<StackPanel x:Name="stkWaitingPatients" Width="300" Margin="0,0,0,-3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Waiting Patients:" VerticalAlignment="Center" FontSize="21.333" Margin="0,0,0,20"/>
<TextBlock HorizontalAlignment="Right" Margin="0,0,38.245,0" Width="139" Height="16"
Text="Minutes Waiting" TextWrapping="Wrap" Foreground="#FF9C2525" FontWeight="Bold" VerticalAlignment="Bottom"
TextAlignment="Right"/>
<!-- Too be implemented, this is the wait animation -->
<!--<Image x:Name="PollGif" Visibility="{Binding Loading}"
HorizontalAlignment="Left" Margin="100,0,0,0" Width="42.5" Height="42.5"
Source="Images/loading-gif-animation.gif" Stretch="Fill"/>-->
</StackPanel>
<ListBox x:Name="lstWaitingPatients"
DataContext="{Binding Mode=OneWay}" ItemsSource="{Binding Mode=OneWay}"
IsSynchronizedWithCurrentItem="true"
ItemTemplate="{StaticResource WaitingPatientsItemTemplate}"
FontSize="21.333" Height="423.291" ScrollViewer.VerticalScrollBarVisibility="Visible"
GotFocus="lstWaitingPatients_GotFocus"
/>
</StackPanel>
</Border>
Ok, but if I just take comment out the assigment line in the codebehind, it does run (albeit with no data in the listbox):
public partial class MainWindow : Window
{
ListBox _activeListBox;
public MainWindow()
{
clsPatients oPatients = new clsPatients(true);
//lstWaitingPatients.DataContext = oPatients;
THANKS!

Resources