How to inherit style from tabitemex infragistics - c#

I am using infragistics tabcontrol controls. My itemcontainer value is based on an object property. To be clear what I mean, look at the following code snippet.
WPF
<Window x:Class="DynamicTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:igWindows="http://infragistics.com/Windows"
xmlns:igDp="http://infragistics.com/DataPresenter"
xmlns:igThemes="http://infragistics.com/Themes"
Title="MainWindow" Height="450" Width="700">
<Grid>
<igWindows:XamTabControl Name="xamTabCtrl" ItemsSource="{Binding Collection}" Theme="Metro">
<igWindows:XamTabControl.ItemContainerStyle>
<Style TargetType="{x:Type igWindows:TabItemEx}" BasedOn="{x:Static igThemes:DataPresenterMetro.LabelPresenter}">
<Setter Property="Header" Value="{Binding Path=Header}"/>
</Style>
</igWindows:XamTabControl.ItemContainerStyle>
<igWindows:XamTabControl.ContentTemplate>
<DataTemplate>
<igDp:XamDataGrid Theme="Metro"
DataSource="{Binding Logins}" IsGroupByAreaExpanded="False" GroupByAreaLocation="None" GroupByAreaMode="DefaultFieldLayoutOnly"/>
</DataTemplate>
</igWindows:XamTabControl.ContentTemplate>
</igWindows:XamTabControl>
</Grid>
</Window>
and the partial class
public partial class MainWindow : Window
{
private ObservableCollection<Model> collection;
public ObservableCollection<Model> Collection
{
get { return collection; }
}
public MainWindow()
{
InitializeComponent();
collection = new ObservableCollection<Model>()
{
new Model() { Header = "Tab1"},
new Model() { Header = "Tab2"},
new Model() { Header = "Tab3"},
new Model() { Header = "Tab4"},
};
DataContext = this;
//xamTabCtrl.ItemsSource = collection;
}
}
and the model
public class Model
{
private ObservableCollection<Login> _logins = new ObservableCollection<Login>()
{
new Login() { User = "User", Password = "Password"},
new Login() { User = "User", Password = "Password"},
new Login() { User = "User", Password = "Password"},
};
public string Header { get; set; }
public ObservableCollection<Login> Logins
{
get { return _logins; }
}
}
when I compile the application I've got the error
{"Can only base on a Style with target type that is base type 'TabItemEx'."}
Who can I inherit the style from infragistics theme?

I found it. I found the class for inheritance.
<Style TargetType="{x:Type igWindows:TabItemEx}" BasedOn="{x:Static igThemes:PrimitivesMetro.TabItemEx}">
<Setter Property="Header" Value="{Binding Path=Header}"/>
</Style>

Related

WPF TreeView Items binding in ViewModel not working

I'm trying to display a treeview in my application but somehow I can't get the binding to work and application displays a blank treeview. Here's the source code.
MainWindow.xaml
<Window x:Class="TreeViewTest.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:TreeViewTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<ListBox x:Name="listbox" MinWidth="200" MinHeight="300">
<TreeView x:Name="treeView" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Regions}"
MinWidth="200" MinHeight="300">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Region}" ItemsSource="{Binding Customers}" >
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:CustomerDataHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility" Value="Visible"/>
</Style>
</CheckBox.Style>
</CheckBox>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Customer}" >
<CheckBox Content="{Binding Name}" IsChecked="{Binding Path=(local:CustomerDataHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility" Value="Visible"/>
</Style>
</CheckBox.Style>
</CheckBox>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</ListBox>
<Button Content="?" Click="Button_Click" />
<TextBlock x:Name="textBoxCrew"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public ObservableCollection<Region> Regions { get; }
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string crew = "";
foreach (Region Region in this.Regions)
foreach (Customer Customer in Region.Customers)
if (CustomerDataHelper.GetIsChecked(Customer) == true)
crew += Customer.Name + ", ";
crew = crew.TrimEnd(new char[] { ',', ' ' });
this.textBoxCrew.Text = "Selected customers: " + crew;
}
}
MainWindowViewModel.cs
class MainWindowViewModel
{
public MainWindowViewModel()
{
Regions = new ObservableCollection<Region>();
Regions.Add(new Region() { Name = "North", Customers = new List<Customer>() { new Customer() { Name = "N1" }, new Customer() { Name = "N2" } } });
Regions.Add(new Region() { Name = "East", Customers = new List<Customer>() { new Customer() { Name = "E1" }, new Customer() { Name = "E2" } } });
Regions.Add(new Region() { Name = "South", Customers = new List<Customer>() { new Customer() { Name = "S1" } } });
foreach (Region Region in this.Regions)
foreach (Customer Customer in Region.Customers)
Customer.SetValue(CustomerDataHelper.ParentProperty, Region);
}
public ObservableCollection<Region> Regions { get; }
}
Customers.cs
public class Region : DependencyObject
{
public string Name { get; set; }
public List<Customer> Customers { get; set; }
}
public class Customer : DependencyObject
{
public string Name { get; set; }
}
CustomerDataHelper.cs
public class CustomerDataHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(CustomerDataHelper), new PropertyMetadata(false, new PropertyChangedCallback(OnIsCheckedPropertyChanged)));
public static void SetIsChecked(DependencyObject element, bool? IsChecked)
{
element.SetValue(CustomerDataHelper.IsCheckedProperty, IsChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?)element.GetValue(CustomerDataHelper.IsCheckedProperty);
}
public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(object), typeof(CustomerDataHelper));
public static void SetParent(DependencyObject element, object Parent)
{
element.SetValue(CustomerDataHelper.ParentProperty, Parent);
}
public static object GetParent(DependencyObject element)
{
return (object)element.GetValue(CustomerDataHelper.ParentProperty);
}
private static void OnIsCheckedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Region && ((bool?)e.NewValue).HasValue)
foreach (Customer p in (d as Region).Customers)
CustomerDataHelper.SetIsChecked(p, (bool?)e.NewValue);
if (d is Customer)
{
int checkedCount = ((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as Region).Customers.Where(x => CustomerDataHelper.GetIsChecked(x) == true).Count();
int uncheckedCount = ((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as Region).Customers.Where(x => CustomerDataHelper.GetIsChecked(x) == false).Count();
if (uncheckedCount > 0 && checkedCount > 0)
{
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, null);
return;
}
if (checkedCount > 0)
{
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, true);
return;
}
CustomerDataHelper.SetIsChecked((d as Customer).GetValue(CustomerDataHelper.ParentProperty) as DependencyObject, false);
}
}
}
If I add the view model ctor code in the code behind ctor and run, it works and I can see the tree view items displayed. Can't seem to figure out what I'm missing.

WPF - How can I use an ObservableCollection of viewmodels to show TabItems?

I have a window which contains a TabControl and I would like to have TabItems generated based on user actions. Inside the TabItems I would like to display a UserControl which uses a ViewModel.
I can get everything to display properly, however when the UserControl's ViewModel is updated, the changes are not reflected in the TabItem.
Consider the following simplified example:
MainWindowViewModel.cs
public class MainWindowViewModel : ViewModel
{
public MainWindowViewModel()
{
MyControls = new ObservableCollection<MyControlViewModel>();
}
private ObservableCollection<MyControlViewModel> _myControls;
public ObservableCollection<MyControlViewModel> MyControls
{
get { return _myControls; }
set
{
_myControls = value;
RaisePropertyChangedEvent(nameof(MyControls));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
private static MainWindowViewModel _vm;
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
_vm = DataContext as MainWindowViewModel;
var myItem1 = new MyItem("Item1");
var myItem2 = new MyItem("Item2");
var myControlVm = new MyControlViewModel(new ObservableCollection<MyItem> { myItem1, myItem2 });
_vm.MyControls.Add(myControlVm);
}
}
MainWindow.xaml
<Window x:Class="TabControlTest.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:TabControlTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<TabControl ItemsSource="{Binding MyControls}">
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:MyControlViewModel}">
<local:MyControl />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
MyControlViewModel.cs
public class MyControlViewModel : ViewModel
{
public MyControlViewModel(ObservableCollection<MyItem> items)
{
MyItems = items;
}
private ObservableCollection<MyItem> _myItems;
public ObservableCollection<MyItem> MyItems
{
get { return _myItems; }
set
{
_myItems = value;
RaisePropertyChangedEvent(nameof(MyItems));
}
}
}
MyControl.xaml.cs
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var vm = DataContext as MyControlViewModel;
foreach (var item in vm.MyItems)
{
item.ShouldBold = !item.ShouldBold;
}
}
}
MyControl.xaml
<UserControl x:Class="TabControlTest.MyControl"
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:local="clr-namespace:TabControlTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ListBox ItemsSource="{Binding MyItems}" MouseDoubleClick="ListBox_MouseDoubleClick">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Content" Value="{Binding Label}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<DataTrigger Binding="{Binding ShouldBold}" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
</Grid>
</UserControl>
MyItem.cs
public class MyItem : ViewModel
{
public MyItem(string label)
{
Label = label;
}
private string _label;
public string Label
{
get { return _label; }
set
{
_label = value;
RaisePropertyChangedEvent(nameof(Label));
}
}
private bool _shouldBold;
public bool ShouldBold
{
get { return _shouldBold; }
set
{
_shouldBold = value;
RaisePropertyChangedEvent(nameof(ShouldBold));
}
}
}
When I double-click on the MyControl in the MainWindow I would expect the items to be displayed in bold via the ListBox_MouseDoubleClick method, however the style is not applying. When I step through the ListBox_MouseDoubleClick method, I can see that the ShouldBold is being updated correctly, but again the style is not applying.
Is there another way I should structure this or something else I need to do to have the style apply? Any help is appreciated!
Edit
Here's my ViewModel.cs
public class ViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Your ViewModel class should implement INotifyPropertyChanged:
public class ViewModel : INotifyPropertyChanged
...

bind Menu using MVVM throw exception

In my View I have a Menu Control which is binded to my ViewModel's Property becauase I want to populate it dynamically.I created a seperated class for my Menu .
Here is my My menu class:
public class MenuItemViewModel : ViewModelBase
{
internal MenuItemViewModel()
{
}
private string _menuText;
public string MenuText
{
get { return _menuText; }
set
{
if (_menuText == value)
return;
_menuText = value;
RaisePropertyChanged("MenuText");
}
}
private ObservableCollection<MenuItemViewModel> _children;
public ObservableCollection<MenuItemViewModel> Children
{
get { return _children; }
set
{
_children = value;
RaisePropertyChanged("Children");
}
}
}
and In my MainViewModel I created an Collection property of my MenuItemViewModel
here is my MainViewModel:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
LoadMainMenu();
}
#region Menu
private ObservableCollection<MenuItemViewModel> _topMenuItems;
public ObservableCollection<MenuItemViewModel> TopMenuItems
{
get { return _topMenuItems; }
set
{
if (_topMenuItems == value)
return;
_topMenuItems = value;
RaisePropertyChanged("TopMenuItems");
}
}
public void LoadMainMenu()
{
IList<MenuItemViewModel> fileMenuItems = PopulateFileMenuEntries();
_topMenuItems.Add(new MenuItemViewModel() { MenuText = "_File", Children = new ObservableCollection<MenuItemViewModel>(fileMenuItems) });
}
private IList<MenuItemViewModel> PopulateFileMenuEntries()
{
List<MenuItemViewModel> fileMenuItems = new List<MenuItemViewModel>();
fileMenuItems.Add(new MenuItemViewModel() { MenuText = "Open _Recent" });
return fileMenuItems;
}
}
here is my XAML:
<Window.Resources>
<WpfApplication3_ViewModel:MainViewModel x:Key="MainViewModelDataSource"
d:IsDataSource="True" />
</Window.Resources>
<Grid DataContext="{StaticResource MainViewModelDataSource}">
<Menu
ItemsSource="{Binding TopMenuItems}"
Margin="12,0,50,237">
<Menu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header"
Value="{Binding MenuText}" />
<Setter Property="ItemsSource"
Value="{Binding Children}" />
<Style.Triggers>
<DataTrigger Binding="{Binding }"
Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Separator Style="{StaticResource {x:Static MenuItem.SeparatorStyleKey}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Menu.Resources>
</Menu>
</Grid>
When the application run it throw an exception "Exception has been thrown by the target of an invocation."
What is wrong with my code
I have had similar problem and I tracked it down to an uninitialised variable. Your _topMenuItems in your Constructor should be
new ObservableCollection<MenuItemViewModel>()
or
ObservableCollection<MenuItemViewModel> _topMenuItems = new ObservableCollection<MenuItemViewModel>();

XamDataGrid with XamComboEditor not keeping selection

I'm having an issue with a XamDataGrid that is hosting a XamComboBox in one of the fields. If the user uses the mouse to put focus into the combo box column and then uses a letter on the keyboard to select an item and then presses tab to move to the next column, the selection in the combo is lost.
I'm not sure whether this is a bug in the controls or just the way I'm using them, I've tried to work round the issue by using the CellDeactivating event, but I think the value has already been lost by that point. I'm using version 11.2.20112.2316 of the controls.
I've also posted this to the Infragistics forums.
This little bit of XAML and code-behind demonstrates the issue.
<Window x:Class="DataGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ig="http://infragistics.com/DataPresenter"
xmlns:igEditors="http://infragistics.com/Editors"
Title="MainWindow" Height="350" Width="525">
<ig:XamDataGrid DataSource="{Binding MyData}" >
<ig:XamDataGrid.FieldLayoutSettings>
<ig:FieldLayoutSettings AllowAddNew="True" AutoGenerateFields="False" />
</ig:XamDataGrid.FieldLayoutSettings>
<ig:XamDataGrid.FieldLayouts>
<ig:FieldLayout>
<ig:Field Name="Code">
<ig:Field.Settings>
<ig:FieldSettings EditorType="{x:Type igEditors:XamComboEditor}">
<ig:FieldSettings.EditorStyle>
<Style TargetType="{x:Type igEditors:XamComboEditor}">
<Setter Property="ValuePath" Value="Code" />
<Setter Property="DisplayMemberPath" Value="Description"/>
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=MyData2}" />
</Style>
</ig:FieldSettings.EditorStyle>
</ig:FieldSettings>
</ig:Field.Settings>
</ig:Field>
<ig:Field Name="Description"></ig:Field>
</ig:FieldLayout>
</ig:XamDataGrid.FieldLayouts>
</ig:XamDataGrid>
</Window>
-
using System;
using System.ComponentModel;
using System.Windows;
namespace DataGridTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyData = new BindingList<MyModel>
{
new MyModel {Code = "T1", Description = "Test 1"},
new MyModel {Code = "T2", Description = "Test 2"}
};
MyData2 = new BindingList<MyModel>
{
new MyModel {Code = "T1", Description = "Test 3"},
new MyModel {Code = "T2", Description = "Test 4"}
};
DataContext = this;
}
public BindingList<MyModel> MyData { get; set; }
public BindingList<MyModel> MyData2 { get; set; }
}
public class MyModel
{
public string Code { get; set; }
public string Description { get; set; }
}
}
I have been looking into this and it seems like that there is an internal issue with the XamComboEditor, XamDataGrid and selection.
Also there are more details for this in the duplicate forum thread in the Infragistics' forum here:
http://www.infragistics.com/community/forums/p/84127/420015.aspx

Unable to bind a ResourceDictionary item to Rectangle.Child

When I try to bind a ResourceDictionary item against Rectangle.Child, I get an exception:
ArgumentException: Value does not fall within the expected range.
Here is an example:
<UserControl.Resources>
<local:PersonConverter x:Key="MyConverter"/>
</UserControl.Resources>
<ListBox ItemsSource="{Binding Persons}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Child="{Binding Gender, Converter={StaticResource MyConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the code behind:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
Persons = new List<Person> {new Person("Female"), new Person("Male")};
}
public List<Person> Persons { get; private set; }
}
public class PersonConverter : IValueConverter
{
private ResourceDictionary Items { get; set; }
public PersonConverterRes()
{
Items = new ResourceDictionary
{
{"Male", new Canvas() {
Background = new SolidColorBrush(Colors.Blue),
Height = 100, Width = 100}},
{"Female", new Canvas() {
Background = new SolidColorBrush(Colors.Magenta),
Height = 100, Width = 100}}
};
}
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Items[value.ToString()];
}
...
}
public class Person
{
public Person(String gender)
{
Gender = gender;
}
public String Gender { get; private set; }
}
But if I replace the ResourceDictionary with a plain Dictionary<String, UIElement> the binding works fine:
public class PersonConverter : IValueConverter
{
private Dictionary<String, UIElement> Items { get; set; }
public PersonConverterRes()
{
Items = new Dictionary<String, UIElement>
{
{"Male", new Canvas() {
Background = new SolidColorBrush(Colors.Blue),
Height = 100, Width = 100}},
{"Female", new Canvas() {
Background = new SolidColorBrush(Colors.Magenta),
Height = 100, Width = 100}}
};
}
...
}
Does anybody know what is causing this exception?
Note:
I have tried this under WinRT as well. There, the code doesn't throw an exception, but the binding still doesn't work if I use a ResourceDictionary. I guess it's probably failing silently.
You can not use databinding to bind to the Child property of a Border since it is not a DependencyProperty. This is why your ResourceDictionary approach does not work.
Also, databinding in WPF/Silvelight/WinRT fails silently by design (it's a feature, and a very useful one if used correctly), so your guess would be right on that.
Don't do this.
More elegant to set a the Canvas.Background with trigger
<ListBox ItemsSource="{Binding Persons}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border <!-- set properties --> >
<Canvas Height="100" Width="100">
<Canvas.Style>
<Style TargetType="Canvas">
<Style.Triggers>
<DataTrigger Binding={Binding Gender} Value="Male">
<Setter Property="Background" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding={Binding Gender} Value="Female">
<Setter Property="Background" Value="Magenta"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Canvas.Style>
</Canvas>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Categories