Binding DataGridComboBoxColumn to enum value - wpf

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

Related

Designdata via xaml in WPF VS20019

I have been struggling with trying to make sample data works out of a XAML. I have tried using this guide https://blogs.msdn.microsoft.com/wpfsldesigner/2010/06/30/sample-data-in-the-wpf-and-silverlight-designer/ and this guide https://learn.microsoft.com/en-us/windows/uwp/data-binding/displaying-data-in-the-designer to get information on the subject, but besides those pages, I haven't found any other sources with good enough information. And to try an understand this mode I made a simple WPF project to test it.
<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:local="clr-namespace:WpfApp1" mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignData Source=DesignData.xaml}">
<Window.DataContext>
<local:Viewmodel/>
</Window.DataContext>
<Grid>
<TextBlock HorizontalAlignment="Left" Margin="119,104,0,0" TextWrapping="Wrap" Text="{Binding TextBlockValue}" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="255,101,0,0" TextWrapping="Wrap" Text="{Binding TextboxValue}" VerticalAlignment="Top" Width="120"/>
<Border Margin="542,71,80,223" BorderThickness="2">
<Border.BorderBrush>Black</Border.BorderBrush>
<ItemsControl ItemsSource="{Binding Persons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding Lastname}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</Grid>
</Window>
This is my simple WPF window that has a textbox, textblock and a ItemsControl. It has a DataContext set with a Viewmodel and a design data DataContext. Viewmodel is as follows:
public class Viewmodel : INotifyPropertyChanged
{
public Viewmodel()
{
Persons = new ObservableCollection<Person>();
Persons.Add(new Person{FirstName = "first one", Lastname = "last one"});
Persons.Add(new Person{FirstName = "John", Lastname = "Doe"});
Persons.Add(new Person{FirstName = "Jane", Lastname = "Doe"});
TextBlockValue = "This is a textBlock";
textboxValue = "This is a textBox";
}
private string textBlockValue;
public string TextBlockValue
{
//<Omitted for readability>
}
private string textboxValue;
public string TextboxValue
{
//<Omitted for readability>
}
public ObservableCollection<Person> Persons { get; set; }
//<Omitted INotifyPropertyChanged implementation for readability>
}
public class Person : INotifyPropertyChanged
{
private string firstName;
public string FirstName
{
//<Omitted for readability>
}
private string lastname;
public string Lastname
{
//<Omitted for readability>
}
public event PropertyChangedEventHandler PropertyChanged;
//<Omitted INotifyPropertyChanged implementation for readability>
}
And my design data:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<local:Viewmodel TextboxValue="Box Test" TextBlockValue="Block test" x:Key="Viewmodel">
<local:Viewmodel.Persons>
<local:Person Lastname="test" FirstName="test"/>
<local:Person Lastname="test" FirstName="test"/>
<local:Person Lastname="test" FirstName="test"/>
</local:Viewmodel.Persons>
</local:Viewmodel>
</ResourceDictionary>
When I add my ViewModel datacontext to the xaml I can see that the values show up in the designer. But when I assign my d:datacontext, the test data does not appear as expected. I think it is because my design data is wrong, but I cannot figure out why it is wrong.
The contents of your DesignData.xaml file should look like this, i.e. it shouldn't contain a ResourceDictionary:
<local:Viewmodel xmlns:local="clr-namespace:WpfApp1" TextboxValue="Box Test" TextBlockValue="Block test">
<local:Viewmodel.Persons>
<local:Person Lastname="test" FirstName="test"/>
<local:Person Lastname="test" FirstName="test"/>
<local:Person Lastname="test" FirstName="test"/>
</local:Viewmodel.Persons>
</local:Viewmodel>
You may also want to set the Build Action of the file to DesignData.

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.

Binding to a list of FontWeight and FontStyle values

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}}" />

MVVM: Binding a ViewModel which takes constructor args to a UserControl

My WPF app has a MainWindow containing a usercontrol called TvshowGridView.
MainWindow:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NevermissClient"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:views="clr-namespace:NevermissClient.Views"
x:Class="NevermissClient.MainWindow"
x:Name="Window">
<Grid x:Name="LayoutRoot">
<views:TvshowGridView x:Name="TheTvshowGridView" Margin="8,8,8,58.96" Grid.Row="1"/>
</Grid>
</Window>
TvshowGridView:
<UserControl
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:viewModels="clr-namespace:NevermissClient.ViewModels"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
x:Class="NevermissClient.Views.TvshowGridView"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<telerik:RadGridView x:Name="TvshowGrid" d:LayoutOverrides="Width, Height" AutoGenerateColumns="False" ItemsSource="{Binding AllEpisodes}" IsReadOnly="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding TvshowName, Mode=TwoWay}" Header="Tvshow Name" IsReadOnly="False"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Name, Mode=TwoWay}" Header="Episode Name"/>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Airdate, Mode=TwoWay}" Header="Airdate"/>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
</UserControl>
The view model, TvshowGridViewModel, that I wish to bind to the TvshowGridView has a constructor that takes arguments.
public class TvshowGridViewModel : BaseViewModel
{
private EpisodeRepository _episodeRepository;
private TvshowRepository _tvshowRepository;
public ObservableCollection<EpisodeViewModel> AllEpisodes { get; private set; }
public TvshowGridViewModel(EpisodeRepository episodeRepository, TvshowRepository tvshowRepository)
{
_episodeRepository = episodeRepository;
_tvshowRepository = tvshowRepository;
CreateAllEpisodes();
}
...
}
These arguments are defined in MainWindowViewModel, the view model connected to the MainWindow. - So this seems like the logical place to create the TvshowGridViewModel.
public class MainWindowViewModel : BaseViewModel
{
readonly TvshowGridViewModel _tvshowGridViewModel;
readonly EpisodeRepository _episodeRepository;
readonly TvshowRepository _tvshowRepository;
public MainWindowViewModel()
{
_episodeRepository = new EpisodeRepository("c:\data.xml");
_tvshowRepository = new TvshowRepository("c:\data.xml");
_tvshowGridViewModel = new TvshowGridViewModel(_episodeRepository, _tvshowRepository);
}
public TvshowGridViewModel TvshowGridViewModel { get; }
...
}
How can I bind the instantiated TvshowGridViewModel to the TvshowGridView? (Avoiding codebehind)
Thanks!
Assuming that your MainWindows Datacontext is an instance of MainWindowViewModel, you can bind the usercontrol to TvshowGridViewModel like this:
<Window>
...
<Grid x:Name="LayoutRoot">
<views:TvshowGridView DataContext={Binding TvshowGridViewModel} x:Name="TheTvshowGridView" Margin="8,8,8,58.96" Grid.Row="1"/>
</Grid>
You also should change the TvshowGridViewModel property code like shown:
public TvshowGridViewModel TvshowGridViewModel
{ get{return _tvshowGridViewModel;} }

WPF: Setting a binding for all TreeViewItem instance

Greetings,
I'm using WPF with a Model-View-ViewModel pattern, and I have a view model with an IsSelected property which I want to bind to a TreeViewItem's IsSelected property for all TreeViewItems in the scope. I'm attempting to do this with a Style and a Setter. This works apparently for the root-level TreeViewItems, but not for their children. Why is this? How can I have this apply to all TreeViewItem controls?
Here is the view XAML:
<UserControl x:Class="MyApp.AllAreasView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:MyApp="clr-namespace:MyApp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="700">
<UserControl.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected"
Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
<MyApp:CountVisibilityConverter x:Key="CountVisibilityConverter" />
<HierarchicalDataTemplate x:Key="AreaTemplate"
DataType="AreaViewModel"
ItemsSource="{Binding Path=SubareasCollectionView}">
<WrapPanel>
<TextBlock Text="{Binding Path=Name}" Margin="0 0 8 0" />
<TextBlock DataContext="{Binding Path=Subareas}"
Text="{Binding Path=Count, StringFormat= (\{0\})}"
Visibility="{Binding Path=Count, Converter={StaticResource CountVisibilityConverter}}" />
</WrapPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<TreeView ItemsSource="{Binding TopLevelAreas}"
ItemTemplate="{StaticResource AreaTemplate}">
</TreeView>
</UserControl>
I think we'll need more info to answer your question. Specifically, what your view model(s) look like. Below is an example you can copy and paste that works fine.
Window1.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:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="{Binding Background}"/>
</Style>
<HierarchicalDataTemplate x:Key="ItemTemplate" DataType="local:DataItem" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource ItemTemplate}"/>
</Window>
Window1.xaml.cs:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Media;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
var dis = new ObservableCollection<DataItem>();
var di = new DataItem() { Name = "Top", Background = Brushes.Red };
di.Children.Add(new DataItem() { Name = "Second", Background = Brushes.Blue });
dis.Add(di);
DataContext = dis;
}
}
public class DataItem
{
public DataItem()
{
Children = new ObservableCollection<DataItem>();
}
public string Name
{
get;
set;
}
public ICollection<DataItem> Children
{
get;
set;
}
public Brush Background
{
get;
set;
}
}
}
working with view models you will get very friendly with the ItemContainerStyle property. what you were doing in your code set the data template for the root level. what you want to do is style each of the items in the treeview, which you can do like so.
<TreeView ItemsSource="{Binding TopLevelAreas}"
ItemContainerStyle="{StaticResource AreaTemplate}">
</TreeView>
enjoy
You have to use as mentioned below. Make use of BasedOn option
<TreeView ItemsSource="{Binding TopLevelAreas}">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource StyleKey}"/>
</TreeView.Resources>
</TreeView>

Resources