OK button in dialog not enabling - c#

I am building a WPF application using MVVM Light. In it I have a dialog box. The XAML:
<Window x:Class="ParserEditor.NewParserDialog"
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:ParserEditor"
xmlns:ignore="http://www.galasoft.ch/ignore"
mc:Ignorable="d ignore"
DataContext="{Binding NewParser, Source={StaticResource Locator}}"
Title="New Parser..."
SizeToContent="Height"
Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
<BitmapImage x:Key="ErrorImage" UriSource="Resources/Error.png" />
<local:BooleanToVisibilityConverter x:Key="BoolToVisiblity" True="Visible" False="Collapsed" />
<ControlTemplate x:Key="InputErrorTemplate">
<DockPanel LastChildFill="True">
<Image DockPanel.Dock="Right"
Height="16"
Margin="5"
Source="{StaticResource ErrorImage}"
ToolTip="Contains invalid data"
VerticalAlignment="Center"
Width="16" />
<Border BorderBrush="Red"
BorderThickness="2">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<Style TargetType="ComboBox">
<Setter Property="Margin" Value="5,4,26,4" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
<RowDefinition Height="10" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Name="PromptLabel"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="0"
Text="{Binding Path=Prompt, Mode=TwoWay}"
Visibility="{Binding Path=HasPrompt, Converter={StaticResource BoolToVisiblity}}"/>
<TextBlock Name="ParserTypeLabel"
Grid.Column="0"
Grid.Row="2"
Text="Parser Type:" />
<ComboBox Name="ParserTypePicker"
Grid.Column="1"
Grid.Row="2"
ItemsSource="{Binding Path=ParserTypes}"
SelectedItem="{Binding Path=ParserType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
<Grid Name="ButtonGrid"
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Name="OkButton"
Command="{Binding CloseCommand, ValidatesOnDataErrors=True}"
Grid.Column="0"
Content="OK"
IsDefault="True" />
<Button Name="CancelButton"
Grid.Column="1"
Content="Cancel"
IsCancel="True" />
</Grid>
</Grid>
</Window>
The View Model object:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using ParserEditor.Model;
namespace ParserEditor.ViewModel {
public class NewParserViewModel : ViewModelBase, IDataErrorInfo {
private readonly IDataService _dataService;
public string ParserType {
get { return _ParserType; }
set { Set( ref _ParserType, value ); }
}
private string _ParserType;
public ObservableCollection<string> ParserTypes { get; private set; }
public bool HasPrompt {
get { return !string.IsNullOrWhiteSpace( Prompt ); }
}
public string Prompt {
get { return _Prompt; }
set {
Set( ref _Prompt, value );
RaisePropertyChanged( nameof( HasPrompt ) );
}
}
private string _Prompt;
#region CloseCommand
public RelayCommand CloseCommand { get; private set; }
private bool CanCloseDialog() {
return ParserType == DataService.AWK_FORMAT ||
ParserType == DataService.CSHARP_FORMAT ||
ParserType == DataService.REGEX_FORMAT;
}
private void CloseDialog() {
Messenger.Default.Send( new CloseWindowMessage() );
}
#endregion
#region IDataErrorInfo Implementation
public string Error {
get { return this[ "ParserType" ]; }
}
public string this[ string columnName ] {
get {
switch ( columnName ) {
case "ParserType":
return string.IsNullOrWhiteSpace( ParserType ) ? "You must choose a Parser Type" : null;
default:
return null;
}
}
}
#endregion
public NewParserViewModel( IDataService dataService ) {
_dataService = dataService;
CloseCommand = new RelayCommand( CloseDialog, CanCloseDialog );
ParserTypes = new ObservableCollection<string>();
ParserTypes.Add( DataService.AWK_FORMAT );
ParserTypes.Add( DataService.CSHARP_FORMAT );
ParserTypes.Add( DataService.REGEX_FORMAT );
}
}
}
I've placed a breakpoint in the CanCloseDialog method and it only gets hit once, when the dialog is first displayed. If I select a choice in the ComboBox after the dialog is displayed, the OK button doesn't enable.
What am I missing?

I did some more searching & I finally found the answer here. It turns out I had to change the
using GalaSoft.MvvmLight.Command;
statement to
GalaSoft.MvvmLight.CommandWpf;
Doing this, everything works properly.

Try a delegate Func wich call CanCloseDialog instead.
Somehow RelayCommand lose pointer to the method whithout a delegate.
Invoke the delegate in the CanExecute method of the RelayCommand implementation.
Something like :
CloseCommand = new RelayCommand( CloseDialog,() => {return <your condition logic>});

Related

WindowChrome causing issues with view ContentControl binding?

I've been working on a small tool for ISO integration and I decided to use WPF for the UI. I'm also doing my best to follow the MVVM pattern for future projects. For the main window, I decided to use WindowChrome so I could keep resizing with a restyled window, however, when I try to select a different view, it causes a exception. I tested it and it does work fine, but as soon as I try to bind the content to the templates content, it seems to cause issues with changing the current view.
Main window xaml:
<WindowChrome.WindowChrome>
<WindowChrome ResizeBorderThickness="{Binding ResizeBorderThickness}"
CaptionHeight="{Binding TitleHeight}" GlassFrameThickness="0"/>
</WindowChrome.WindowChrome>
<Window.Resources>
<Style TargetType="{x:Type local:OSToolWPF}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border Padding="{Binding OuterMarginThickness}">
<Grid>
<Border CornerRadius="{Binding WindowCornerRadius}"
Background="{StaticResource BackgroundLightBrush}">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" Opacity=".2"/>
</Border.Effect>
</Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding TitleHeightGridLength, FallbackValue=50}"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border CornerRadius="10 10 0 0"
Background="{StaticResource BackgroundDarkBrush}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Viewbox Margin="25 0 0 0" HorizontalAlignment="Left">
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Title}"/>
</Viewbox>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<Button Style="{StaticResource ButtonBase}" Command="{Binding Minimize}" Width="50">
<Image Style="{StaticResource ControlImage}" Source="/Assets/Top/Minimize.png" Stretch="None"/>
</Button>
<Button Style="{StaticResource ButtonBase}" Command="{Binding Maximize}" Width="50">
<Image Style="{StaticResource ControlImage}" Source="/Assets/Top/Windowed.png" Stretch="None"/>
</Button>
<Button Style="{StaticResource ButtonBase}" Command="{Binding Close}" Width="50">
<Image Style="{StaticResource ControlImage}" Source="/Assets/Top/Close.png" Stretch="None"/>
</Button>
</StackPanel>
</Grid>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel>
<Button Style="{StaticResource ButtonBase}" Tag="Registry" Command="{Binding Menu}"
Content="Registry" FontSize="20" Height="50" CommandParameter="{Binding
RelativeSource={RelativeSource Mode=Self}, Path=Tag}"/>
<Button Style="{StaticResource ButtonBase}" Tag="Services" Command="{Binding Menu}"
Content="Services" FontSize="20" Height="50" CommandParameter="{Binding
RelativeSource={RelativeSource Mode=Self}, Path=Tag}"/>
<Button Style="{StaticResource ButtonBase}" Tag="Visuals" Command="{Binding Menu}"
Content="Visuals" FontSize="20" Height="50" CommandParameter="{Binding
RelativeSource={RelativeSource Mode=Self}, Path=Tag}"/>
</StackPanel>
<Button Grid.Row="2" Style="{StaticResource ButtonBase}"
Content="Exit" FontSize="20" Command="{Binding Close}"
Height="50"/>
</Grid>
<Border Grid.Column="1">
<ContentControl Content="{TemplateBinding Content}"/>
<Border/>
</Grid>
</Grid>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<ContentControl Content="{Binding CurrentView}"/>
Main window view model (the data binding is done in xaml.cs since it needs a window):
public class OSToolViewModel : BaseViewModel
{
#region Private
private Window wWindow;
private object wCurrentView;
private int wOuterMarginSize = 10;
private int wWindowRadius = 15;
#endregion
public OSToolViewModel(Window window)
{
wWindow = window;
wWindow.StateChanged += (sender, e) =>
{
OnPropertyChanged(nameof(ResizeBorderThickness));
OnPropertyChanged(nameof(OuterMarginSize));
OnPropertyChanged(nameof(OuterMarginThickness));
OnPropertyChanged(nameof(WindowRadius));
OnPropertyChanged(nameof(WindowCornerRadius));
};
Menu = new BaseCommand(e => CurrentView = new ExpanderItemsList());
Minimize = new BaseCommand(e => wWindow.WindowState = WindowState.Minimized);
Maximize = new BaseCommand(e => wWindow.WindowState ^= WindowState.Maximized);
Close = new BaseCommand(e => CloseMessage());
}
#region Voids
private void CloseMessage()
{
if (DialogBox.Show("Would you like to exit?", "", wWindow.Title, DialogBoxButtons.YesNo) == DialogResult.Yes)
{
wWindow.Close();
}
}
#endregion
#region Commands
public BaseCommand Menu { get; set; }
public BaseCommand Minimize { get; set; }
public BaseCommand Maximize { get; set; }
public BaseCommand Close { get; set; }
#endregion
#region Public
public object CurrentView
{
get { return wCurrentView; }
set
{
if (value == wCurrentView)
return;
wCurrentView = value;
OnPropertyChanged(nameof(CurrentView));
}
}
public int ResizeBorder { get; set; } = 6;
public int OuterMarginSize
{
get
{
return wWindow.WindowState == WindowState.Maximized ? 0 : wOuterMarginSize;
}
set
{
wOuterMarginSize = value;
}
}
public int WindowRadius
{
get
{
return wWindow.WindowState == WindowState.Maximized ? 0 : wWindowRadius;
}
set
{
wWindowRadius = value;
}
}
public double TitleHeight { get; set; } = 50;
public Thickness ResizeBorderThickness { get { return new Thickness(ResizeBorder + OuterMarginSize); } }
public Thickness OuterMarginThickness { get { return new Thickness(OuterMarginSize); } }
public CornerRadius WindowCornerRadius { get { return new CornerRadius(WindowRadius); } }
public GridLength TitleHeightGridLength { get { return new GridLength(TitleHeight + ResizeBorder); } }
#endregion
}
The view I'm trying to bind to is a page, so I'm not sure if that would cause issues or not, but I've tried a lot of different combos and the combo I shared causes a exception. If I didn't bind to to the templated content, it would work fine. I'm baffled as to why this happens, and as a side note, the buttons in the window aren't cornered like they should be, so if you have a solution for this too, that would be much appreciated! Thank you and I hope you enjoy your day!
I just realized this issue was because of the fact I was using a Page rather than a UserControl. Switching the view to a UserControl solved the issue. Hopefully this helps if anyone else runs into this issue.

How to open new modal dialog using prism in wpf

I have done opening the modal dialog in Wpf MVVM. But I am new to prism. I have tried the following code in MVVM. Now its working fine. But I want to do the same concept using prism with ribbon window. In the below code I have not used ribbon window, instead of ribbon window I used the button. please refer the below code,
MainWindow.xaml
<Window.Resources>
<DataTemplate DataType="{x:Type vm:ModalDialogViewModel}">
<view:ModalDialog />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">
<Grid>
<Button
Width="150"
Height="25"
Margin="0,10,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding Path=LoadViewCommand}"
Content="Show Modal Dialog" />
</Grid>
</Grid>
<Grid Visibility="{Binding IsCloseModalWindow, Converter={StaticResource BooleanToVisibilityConverter}}">
<Border Background="#90000000">
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="0">
<Border.BitmapEffect>
<DropShadowBitmapEffect
Direction="270"
Opacity="0.5"
ShadowDepth="0.7"
Color="Black" />
</Border.BitmapEffect>
<ContentControl Content="{Binding Path=CurrentViewModel}" />
</Border>
</Border>
</Grid>
</Grid>
MainWindowViewModel
public class MainWindowViewModel : ViewModelBase, ICloseWindow
{
private ICommand loadViewCommand;
private ViewModelBase _currentViewModel;
public ViewModelBase CurrentViewModel
{
get { return _currentViewModel; }
set
{
_currentViewModel = value;
this.OnPropertyChanged("CurrentViewModel");
}
}
private bool isCloseModalWindow = false;
public bool IsCloseModalWindow
{
get { return isCloseModalWindow; }
set { isCloseModalWindow = value; OnPropertyChanged("IsCloseModalWindow"); }
}
public MainWindowViewModel()
{
}
public ICommand LoadViewCommand => loadViewCommand ?? (loadViewCommand = new RelayCommand(showView, canShowView));
private void showView(object obj)
{
IsCloseModalWindow = true;
CurrentViewModel = new ModalDialogViewModel(new ModalDialogModel() { Name = "New Modal Window" }, this);
}
private bool canShowView(object obj)
{
return true;
}
public void closeWindow()
{
IsCloseModalWindow = false;
}
}
ModalDialog
<Grid MinWidth="300" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
MinHeight="30"
Background="SkyBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Width="40"
Height="25"
Content="X"
BorderThickness="0"
Background="Transparent"
Foreground="White"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding CancelCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
ToolTip="Close" />
</Grid>
</Grid>
<Grid Grid.Row="1" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
Content="Name"
Style="{StaticResource commonMargin}" />
<Label
Grid.Row="0"
Grid.Column="1"
Content=":"
Style="{StaticResource commonMargin}" />
<TextBox
Grid.Row="0"
Grid.Column="2"
Width="100"
Text="{Binding Path=Name}"
Style="{StaticResource commonTimerMargin}" />
</Grid>
<Grid
Grid.Row="2"
Margin="0,0,15,10"
HorizontalAlignment="Right">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="0"
Width="80"
Height="30"
Margin="0,0,10,0"
Background="White"
Command="{Binding CancelCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
Content="CANCEL" />
<Button
Grid.Column="1"
Width="80"
Height="30"
Background="SkyBlue"
Command="{Binding ApplyCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
Content="APPLY"
Foreground="White" />
</Grid>
</Grid>
ModalDialogViewModel
public class ModalDialogViewModel : ViewModelBase
{
private ICommand cancelCommand;
public ModalDialogModel Model { get; private set; }
private ICloseWindow _closeWindow;
public ModalDialogViewModel(ModalDialogModel modalDialogModel, ICloseWindow closeWindow)
{
this.Model = modalDialogModel;
this._closeWindow = closeWindow;
}
public ICommand CancelCommand => cancelCommand ?? (cancelCommand = new RelayCommand(CloseWindow, CanCloseWindow));
private void CloseWindow(object obj)
{
_closeWindow.closeWindow();
}
private bool CanCloseWindow(object obj)
{
return true;
}
}
My Requirement is when user click the ribbon window button the modal dialog is open. The Shell window is a ribbon window. I have added HomeTab module and many other modules as separate class library.
You can do it like this in .xaml:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://prismlibrary.com/"
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding PopUpDialogActionBinding}"> '<-- Here is your action binding
<prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="False">
<prism:PopupWindowAction.WindowStyle>
<Style TargetType="Window">
<Setter Property="Icon" Value="IconPath"/>
<Setter Property="Height" Value="400"/>
<Setter Property="Width" Value="400"/>
</Style>
</prism:PopupWindowAction.WindowStyle>
<prism:PopupWindowAction.WindowContent>
<views:YourCustomView /> ' <--- Put your view into the dialog
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
<Grid>
...
</Grid>
I did it as in the example 28:
https://github.com/PrismLibrary/Prism-Samples-Wpf

Can I make this block of XAML into a reusable "control"?

I have a Grid, and in that grid, I have this:
<StackPanel Grid.Row="2"
Grid.Column="0">
<Grid x:Name="GridButtonItem" Margin="30,0,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Setter Property="Background"
Value="Transparent" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="#332a8dd4" />
</Trigger>
<Trigger Property="IsMouseOver"
Value="False">
<Setter Property="Background"
Value="Transparent" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Image Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Margin="3"
Source="{dx:DXImageOffice2013 Image=Windows_32x32.png}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Grid.Row="0"
Grid.Column="1"
Margin="10,3,3,0"
Text="Application Log" />
<TextBlock Grid.Row="1"
Grid.Column="1"
Margin="10,0,3,3"
Text="C:\Program Files (x86)\ATI Technologies\ATI.ACE\MOM-InstallProxy" />
</Grid>
</StackPanel>
The StackPanel is actually meant to hold many of the GridButtonItem items. Is there a way that I can somehow make a "template" of GridButtonItem and then for each one I want to add to the StackPanel, just set the Image and Text properties?
Something like this (just pseudo-code for demonstration):
<StackPanel>
<Grid Template="myGridItemTemplate">
<Setter Property="Image" Value="img1.png"/>
<Setter Property="Text1" Value="button1 Text"/>
<Setter Property="Text2" Value="button2 Text"/>
</Grid>
<Grid Template="myGridItemTemplate">
<Setter Property="Image" Value="img1.png"/>
<Setter Property="Text1" Value="button1 Text"/>
<Setter Property="Text2" Value="button2 Text"/>
</Grid>
<Grid Template="myGridItemTemplate">
<Setter Property="Image" Value="img1.png"/>
<Setter Property="Text1" Value="button1 Text"/>
<Setter Property="Text2" Value="button2 Text"/>
</Grid>
</StackPanel>
So each one that is added picks up the row/column definitions, and an embedded Image and two TextBlocks. Then I just set the three properties for each one added.
Is this possible?
You can put your grid control into a UserControl and then reuse the UserControl throughout your project. I have a simple example of doing this with a label and Textbox.
here is the XAML:
<UserControl x:Class="TestVision.CustomControls.LabelAndTextbox"
x:Name="parent"
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:TestVision.CustomControls"
mc:Ignorable="d" >
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=parent}">
<TextBlock Text="{Binding Path=Label}" Width="{Binding Path=LabelWidth}" VerticalAlignment="Center" TextAlignment="Right" Margin="0,0,10,0" Height="22"/>
<TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" Width="{Binding Path=TextboxWidth}" IsReadOnly="{Binding Path=TextboxReadOnly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="{Binding Path=TextboxHorizontalContentAlgnment}"/>
</StackPanel>
</UserControl>
Any properties that you want to be able to set e.g. your image text etc. must be bound to Dependency Properties in the code behind.
Code behind:
public partial class LabelAndTextbox : UserControl
{
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
public String Label
{
get { return (String)GetValue(LabelContent); }
set { SetValue(LabelContent, value); }
}
/// <summary>
/// Identified the Label dependency property
/// </summary>
public static readonly DependencyProperty LabelContent =
DependencyProperty.Register("Label", typeof(string),
typeof(LabelAndTextbox), new PropertyMetadata(""));
public object Text
{
get { return (object)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(object),
typeof(LabelAndTextbox), new PropertyMetadata(null));
public Double LabelWidth
{
get { return (Double)GetValue(LabelWidthProperty); }
set { SetValue(LabelWidthProperty, value); }
}
public static readonly DependencyProperty LabelWidthProperty =
DependencyProperty.Register("LabelWidth", typeof(Double),
typeof(LabelAndTextbox), new PropertyMetadata());
public Double TextboxWidth
{
get { return (Double)GetValue(TextboxWidthProperty); }
set { SetValue(TextboxWidthProperty, value); }
}
public static readonly DependencyProperty TextboxWidthProperty =
DependencyProperty.Register("TextboxWidth", typeof(Double),
typeof(LabelAndTextbox), new PropertyMetadata());
public bool TextboxReadOnly
{
get { return (bool)GetValue(TextboxReadOnlyProperty); }
set { SetValue(TextboxReadOnlyProperty, value); }
}
public static readonly DependencyProperty TextboxReadOnlyProperty =
DependencyProperty.Register("TextboxReadOnly", typeof(bool),
typeof(LabelAndTextbox), new FrameworkPropertyMetadata());
public HorizontalAlignment TextboxHorizontalContentAlgnment
{
get { return (HorizontalAlignment)GetValue(TextboxHorizontalContentAlgnmentProperty); }
set { SetValue(TextboxHorizontalContentAlgnmentProperty, value); }
}
public static readonly DependencyProperty TextboxHorizontalContentAlgnmentProperty =
DependencyProperty.Register("TextboxHorizontalContentAlgnment", typeof(HorizontalAlignment),
typeof(LabelAndTextbox), new FrameworkPropertyMetadata());
public LabelAndTextbox()
{
InitializeComponent();
}
}
you then will need to add a reference in the XAML file to your UserControl like this:
xmlns:Resource="clr-namespace:ProjectNamespace.FolderContainingYourControl"
Resource is a generic identifier you can call it what you like, you can then reference your control in the like this:
<Resource:LabelAndTextblock x:Name="AddressLine1" Label="{Binding LblTxt_AddressLine1}" Text="{Binding AddressLine1, Mode=TwoWay}" Margin="10,5,0,5" LabelWidth="70" TextWidth="250" TextHeight="60"/>
You could do this with a UserControl (two different ways) or a DataTemplate. Let's go with DataTemplate, because stuicidle already ably demonstrated one UserControl approach.
There are a couple of different ways to do this with a DataTemplate, too.
We're going to do something called an implicit DataTemplate. It's created in Resources, but it has no x:Key property, just a DataType="{x:Type local:GridItemViewModel}" property. What that will do is this: Wherever that DataTemplate is in scope, whenever XAML needs to display a GridItemViewModel and nothing is specifying a template to display it in, it'll use that implicit template.
Clear as mud! Welcome to the XAML learning curve.
ViewModels.cs
using System;
using System.ComponentModel;
using System.Windows.Media;
namespace GridItemAnswer
{
#region ViewModelBase Class
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
#endregion INotifyPropertyChanged
}
#endregion ViewModelBase Class
#region GridItemViewModel Class
public class GridItemViewModel : ViewModelBase
{
#region LabelText Property
private String _labelText = null;
public String LabelText
{
get { return _labelText; }
set
{
if (value != _labelText)
{
_labelText = value;
OnPropertyChanged();
}
}
}
#endregion LabelText Property
#region Path Property
private String _path = null;
public String Path
{
get { return _path; }
set
{
if (value != _path)
{
_path = value;
OnPropertyChanged();
}
}
}
#endregion Path Property
#region ImageSource Property
private ImageSource _imageSource = null;
public ImageSource ImageSource
{
get { return _imageSource; }
set
{
if (value != _imageSource)
{
_imageSource = value;
OnPropertyChanged();
}
}
}
#endregion ImageSource Property
}
#endregion GridItemViewModel Class
}
MainWindow.xaml
<Window
x:Class="GridItemAnswer.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:GridItemAnswer"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
<DataTemplate DataType="{x:Type local:GridItemViewModel}">
<StackPanel>
<Grid x:Name="GridButtonItem" Margin="30,0,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#332a8dd4" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Image
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Margin="3"
Source="{Binding Image}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
/>
<TextBlock
Grid.Row="0"
Grid.Column="1"
Margin="10,3,3,0"
Text="{Binding LabelText}"
/>
<TextBlock
Grid.Row="1"
Grid.Column="1"
Margin="10,0,3,3"
Text="{Binding Path}"
/>
</Grid>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ItemsControl>
<local:GridItemViewModel
LabelText="Foo Bar"
Path="c:\foo\bar"
/>
<local:GridItemViewModel
LabelText="Baz Planxty"
Path="c:\baz\planxty"
/>
</ItemsControl>
<Label>
<local:GridItemViewModel
LabelText="A frog walks into a bank asking for a loan"
Path="c:\knick\knack"
/>
</Label>
</StackPanel>
</Grid>
</Window>

ComboBox Event triggers a RadioButton to be checked and populate a listbox

I'm a noob when it comes to XAML and MVVM and am constructing a maintenance screen for our project. The combobox is populated from a list retrieved from a database. When a value selected from the combobox is I want to read one of the properties from the selected item, and check 1 of 2 radiobuttons and then populate a listbox using that same selected item. Here's my xaml:
<UserControl x:Class="StatementPrinting.Client.Views.Setup.TestView"
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"
mc:Ignorable="d"
xmlns:telerikRibbonView="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.RibbonView"
xmlns:examples="clr-namespace:Telerik.Windows.Controls.RichTextBoxUI"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">
<telerik:RadBusyIndicator IsBusy="{Binding BusyDetail.IsBusy}" BusyContent="{Binding}"
IsIndeterminate="True"
BusyContentTemplate="{StaticResource BusyIndicatorBusyContentTemplate}">
<!--<Grid MinWidth="650" MinHeight="400">-->
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Margin="5,0,5,20">
<TextBlock FontWeight="Bold" FontSize="18">Report Group Setup</TextBlock>
<TextBlock>Here you edit whether the selected group is printed or not and what items are part it.</TextBlock>
</StackPanel>
<Grid Grid.Column="0" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Grid.Row="0">
<TextBlock VerticalAlignment="Center" Margin="0,0,15,0">Select a Group:</TextBlock>
<ComboBox x:Name="cmbReportGroup" IsEditable="False" ItemsSource="{Binding ReportGroups}" DisplayMemberPath="Description" SelectedValuePath="Name" SelectedItem="{Binding SelectedReportGroup}" />
</DockPanel>
<DockPanel Grid.Column="1" Grid.Row="0" Margin="40,0,0,0">
<TextBlock VerticalAlignment="Center">Printing?</TextBlock>
<RadioButton x:Name="printYesRadioButton" Margin="10" GroupName="printRadioButtonGroup" Content="Yes">
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbReportGroup, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
<TextBlock Name="Or_TextBlock" VerticalAlignment="Center" Margin="5,10,5,10">or</TextBlock>
<RadioButton x:Name="printNoRadioButton" Margin="10" GroupName="printRadioButtonGroup" Content="No">
<RadioButton.Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="IsEnabled" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cmbReportGroup, Path=SelectedItem}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
</RadioButton>
</DockPanel>
</Grid>
<Grid Grid.Column="0" Grid.Row="2" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="0" Margin="0,0,0,10">
<TextBlock>
Change the items that belong to this group:
</TextBlock>
</StackPanel>
<DockPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2">
<TextBlock DockPanel.Dock="Top" Margin="0,0,0,5">Current Notices:</TextBlock>
</DockPanel>
<DockPanel Grid.Column="2" Grid.Row="1">
<TextBlock DockPanel.Dock="Top" Margin="0,0,0,5">Available Notices:</TextBlock>
</DockPanel>
<DockPanel Grid.Column="0" Grid.Row="2">
<ListBox></ListBox>
</DockPanel>
<DockPanel Grid.Column="1" Grid.Row="2">
<Button DockPanel.Dock="Top" VerticalAlignment="Center" Margin="10">
<Image Source="c:\_MicrosProjects\StatementPrinting\DEV\StatementPrinting\StatementPrinting.Client\Resources\arrow-left-10.png"/>
</Button>
<Button DockPanel.Dock="Top" VerticalAlignment="Center" Margin="10">
<Image Source="c:\_MicrosProjects\StatementPrinting\DEV\StatementPrinting\StatementPrinting.Client\Resources\arrow-right-10.png"/>
</Button>
</DockPanel>
<DockPanel Grid.Column="2" Grid.Row="2">
<ListBox></ListBox>
</DockPanel>
</Grid>
</Grid>
</telerik:RadBusyIndicator>
The codebehind:
using Mbs.Common.Instrumentation;
using Mbs.Mvvm.Core;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Events;
using StatementPrinting.Client.ViewModels.Base;
using StatementPrinting.DataLayer;
using StatementPrinting.Domain;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StatementPrinting.Client.ViewModels.Setup
{
public class TestViewModel : SecurityTabbedWorkspaceViewModelBase
{
public TestViewModel(IScreenViewModel screenVM, string connectionString, IEventAggregator eventAggregator)
{
this.SetNameAndTitle("Report Group Setup");
this.ScreenVM = screenVM;
this.ConnectionString = connectionString;
this.AppEventAggregator = eventAggregator;
this.SetSecurity();
LoadReportGroups();
}
private readonly ObservableCollection<ReportGroup> _ReportGroups = new ObservableCollection<ReportGroup>();
public ObservableCollection<ReportGroup> ReportGroups
{
get { return _ReportGroups; }
}
private string _SelectedIndex;
public string SelectedIndex { get; set; }
private ReportGroup _SelectedReportGroup;
public ReportGroup SelectedReportGroup
{
get { return _SelectedReportGroup; }
set
{
_SelectedReportGroup = value;
MessageBox.Show("Print: " + SelectedReportGroup.Print.ToString());
SetPrintOption(SelectedReportGroup.Print);
this.RaisePropertyChanged("SelectedReportGroup");
}
}
private void SetPrintOption(bool PrintOption)
{
MessageBox.Show("Print 2: " + SelectedReportGroup.Print.ToString());
if (SelectedReportGroup.Print)
{
//printYesRadioButton.IsChecked = true;
}
else
{
//printNoRadioButton.IsChecked = true;
}
}
private void LoadReportGroups()
{
try
{
CancellationToken cancelToken = this.GetCancellationToken();
this.BusyDetail.CanBeCanceled = true;
this.BusyDetail.TurnOnBusyIndicator("Loading...");
Task<List<ReportGroup>> loadTask = Task.Factory.StartNew<List<ReportGroup>>(() =>
{
using (StatementPrintingContext context = new StatementPrintingContext(ContextConnectionStringHelper.GetEntitiesConnectString(this.ConnectionString)))
{
return context.ReportGroups.ToList();
}
},
cancelToken);
var completedTask = loadTask.ContinueWith((t) =>
{
if (t.Exception != null)
{
this.RaiseErrorMessageNotification(t.Exception.ToString());
}
else
{
t.Result.ForEach(r => this.ReportGroups.Add(r));
//
// or
//
//foreach (var r in t.Result.ToList())
//{
// ReportGroups.Add(r);
//}
}
},
cancelToken, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (Exception ex)
{
this.RaiseErrorMessageNotification(ex.ToString());
}
finally
{
this.BusyDetail.TurnOffBusyIndicator();
}
}
private DelegateCommand _SaveChangesCommand;
public DelegateCommand SaveChangesCommand
{
get
{
if (_SaveChangesCommand == null)
{
_SaveChangesCommand = new DelegateCommand(() =>
{
try
{
using (var db = new StatementPrintingContext(ContextConnectionStringHelper.GetEntitiesConnectString(this.ConnectionString)))
{
// ******Do any database changes here!********
// . . .
// . . .
this.SaveChangesCommand.RaiseCanExecuteChanged();
this.RaiseMessageNotification("Changes saved successfully.");
}
}
catch (Exception ex)
{
this.RaiseErrorMessageNotification(ex.Message);
ExceptionLogger.Instance.WriteExceptionTrace(ex, this.GetType().ToString());
}
},
() =>
{
// *******Put conditional code here!***********
// . . .
// . . .
return true;
});
}
return _SaveChangesCommand;
}
}
private DelegateCommand _TestCommand;
public DelegateCommand TestCommand
{
get
{
if (_TestCommand == null)
{
_TestCommand = new DelegateCommand(() =>
{
try
{
this.TestCommand.RaiseCanExecuteChanged();
}
catch (Exception ex)
{
this.RaiseErrorMessageNotification(ex.Message);
ExceptionLogger.Instance.WriteExceptionTrace(ex, this.GetType().ToString());
}
},
() =>
{
return true;
});
}
return _TestCommand;
}
}
}
}
Just to reiterate, a person selects an item from the combobox. When they do that, it reads the print value of that item that is stored in the database and then checks either the "Yes" or "No" radiobutton. This is the main issue I'm having right now. Thanks for your help.
Add a Property in Your ViewModel named it SelectedName and Bind it to SelectedValue of the ComboBox:
<ComboBox x:Name="cmbReportGroup" IsEditable="False" ItemsSource="{Binding ReportGroups}" DisplayMemberPath="Description" SelectedValuePath="Name" SelectedItem="{Binding SelectedReportGroup}" SelectedValue="{Binding SelectedName}" />
and in the ViewModel in the Setter of the SelectedName Property add your code:
public string SelectedName
{
get { return _SelectedName; }
set
{
_SelectedName= value;
this.RaisePropertyChanged("SelectedName");
// do your data retrieving form database ...
CheckPrintYesOrNow();
}
}
for the RadioButton you can use the same way add a bool Property in your ViewModel and bind to.

WPF MVVM changing viewmodel calls dependency property on old viewmodel

I have a TabViewModel wich contains a dependency property CurrentViewModel. The CurrentViewModel property is bound to a ContentControl in the view TabView.xaml. The TabViewModel also contains a command to change the CurrentViewModel to a ProductViewModel:
public class TabViewModel: BaseViewModel
{
public string TabName { get; set; }
//public List<BaseViewModel> ViewModels { get; set; }
private PageViewModel _currentViewModel;
public PageViewModel CurrentViewModel
{
get { return _currentViewModel; }
set
{
_currentViewModel = value;
OnPropertyChanged("CurrentViewModel");
}
}
public TabViewModel(string tabName, PageViewModel currentViewModel)
{
TabName = tabName;
CurrentViewModel = currentViewModel;
}
private ICommand _navigateToProductViewModelCommand;
public ICommand NavigateToProductViewModelCommand
{
get
{
if (_navigateToProductViewModelCommand == null)
{
_navigateToProductViewModelCommand = new DelegateCommand<Product>(
(p) =>
{
CurrentViewModel = new ProductViewModel();
});
}
return _navigateToProductViewModelCommand;
}
}
}
TabView.xaml
<UserControl x:Class="Monitoring_Tool.Views.TabView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ProgressBar Value="{Binding Path=CurrentViewModel.PageProgress}" Height="5" Grid.Row="0" Margin="0,0,0,10">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border BorderThickness="0,0,0,0" Background="LightGray" CornerRadius="0" Padding="0">
<Grid x:Name="PART_Track">
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#00B6FA" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ProgressBar.Style>
</ProgressBar>
<ContentControl Content="{Binding Path=CurrentViewModel}" Grid.Row="1" />
</Grid>
I instantiate the TabViewModel like this:
new TabViewModel("Producten", new ProductsViewModel())
The ProductsView.xaml is shown like it should be. In the ProductsView.xaml I call the command from the TabViewModel like this:
<DataGrid.InputBindings>
<MouseBinding
MouseAction="LeftDoubleClick"
Command="{Binding DataContext.NavigateToProductViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type views:TabView}}}"/>
</DataGrid.InputBindings>
When the datagrid is empty, the command is executed and ProductView.xaml appears like it should be. But when the datagrid is not empty somthing strange happens:
the command is executed, and when I debug I can see that the currentViewModel is changed to ProductViewModel. Then when OnPropertyChanged("CurrentViewModel") is called. There is a set call (value = null) to a depedency property (SelectedAssetCategory) on the ProductsViewModel, wich was replaced and doesn't exits anymore?!
When I put CurrentViewModel = null the same thing happens, I can only do CurrentViewModel = new ProductsViewModel. So I guess it's somthing with updating the UI?
In the App.xaml I defined the following recources:
<DataTemplate DataType="{x:Type viewmodels:TabViewModel}">
<views:TabView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:ProductsViewModel}">
<views:ProductsView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:ProductViewModel}">
<views:ProductView />
</DataTemplate>
The ProductsViewModel looks like this:
class ProductsViewModel: PageViewModel
{
private readonly MonitotingToolEntities _databaseEntities;
public ProductsViewModel()
{
_databaseEntities = new MonitotingToolEntities();
AssetCategories = new ObservableCollection<AssetCategory>(_databaseEntities.AssetCategory.ToList())
{
new AssetCategory() {AssetCategoryID = 0, AssetCategoryName = "Alles"}
};
Results = new ObservableCollection<Product>();
}
public ObservableCollection<AssetCategory> AssetCategories { get; set; }
private AssetCategory _selectedAssetCategory;
public AssetCategory SelectedAssetCategory
{
get { return _selectedAssetCategory; }
set
{
_selectedAssetCategory = value; //this one is called with value = null
OnPropertyChanged("SelectedAssetCategory");
Filter();
}
}
public ObservableCollection<Product> Results { get; set; }
public void Filter()
{
Results.Clear();
List<Product> products =
SelectedAssetCategory.AssetCategoryID == 0
? _databaseEntities.Product.ToList()
: SelectedAssetCategory.Product.ToList();
foreach (Product product in products)
{
Results.Add(product);
}
}
}
ProductsView.xaml:
<UserControl x:Class="Monitoring_Tool.Views.ProductsView"
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:views="clr-namespace:Monitoring_Tool.Views"
xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:viewModels="clr-namespace:Monitoring_Tool.ViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<CollectionViewSource x:Key="CvsAssetCategories" Source="{Binding Path= AssetCategories}" >
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="AssetCategoryID"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<CollectionViewSource x:Key="CvsResults" Source="{Binding Path= Results}" >
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="AssetCategory.AssetCategoryName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<Style TargetType="Image" x:Key="ImageDisabledStyle">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid Margin="0, 0, 0, 10" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Asset Categorie:" Grid.Column="0" VerticalAlignment="Center" Margin="0,0,10,0"/>
<ComboBox Grid.Column="1"
ItemsSource="{Binding Source={StaticResource CvsAssetCategories}}"
DisplayMemberPath="AssetCategoryName"
SelectedItem="{Binding SelectedAssetCategory}"
Margin="0,0,10,0"/>
<TextBlock Text="Zoeken:" Grid.Column="3" VerticalAlignment="Center" Margin="0,0,10,0"/>
<ComboBox Grid.Column="4"
SelectedItem="{Binding SelectedSearchField}"
Margin="0,0,10,0"/>
<TextBox Text="{Binding Path=SearchQuery, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="5" Margin="0,0,10,0">
<TextBox.InputBindings>
<KeyBinding Command="{Binding Path=SearchCommand}" CommandParameter="{Binding SearchQuery}" Key="Enter" />
</TextBox.InputBindings>
</TextBox>
<Button Grid.Column="6"
Command="{Binding SearchCommand}"
CommandParameter="{Binding SearchQuery}"
Padding="5,0,5,0" Margin="0,0,10,0" >
<Button.Content>
<Image Source="/Recourses/SearchIcon.png"
Stretch="None" VerticalAlignment="Top" Style="{Binding Source={StaticResource ImageDisabledStyle}}"/>
</Button.Content>
</Button>
<Button Grid.Column="7"
Command="{Binding CancelSearchCommand}"
IsEnabled="{Binding CancelSearchEnabled}"
Padding="5,0,5,0">
<Button.Content>
<Image Source="/Recourses/CancelSearchIcon.png"
Stretch="None" VerticalAlignment="Top" Style="{Binding Source={StaticResource ImageDisabledStyle}}"/>
</Button.Content>
</Button>
</Grid>
<DataGrid Name="DgProducts" AutoGenerateColumns="False"
RowHeaderWidth="0" Margin="0,0,0,10" Grid.Row="1" IsReadOnly="True"
SelectionMode="Single" CanUserReorderColumns="False"
EnableRowVirtualization="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True"
ItemsSource="{Binding Source={StaticResource CvsResults}}" SelectedItem="{Binding SelectedProduct}">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0"/>
</Style>
</DataGrid.CellStyle>
<DataGrid.InputBindings>
<MouseBinding
MouseAction="LeftDoubleClick"
Command="{Binding DataContext.NavigateToProductViewModelCommand, RelativeSource={RelativeSource AncestorType={x:Type views:TabView}}}"
/>
</DataGrid.InputBindings>
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader" x:Key="DgVerticalColumnHeader">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="270" />
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="LightGray"/>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey }"
Color="Black"/>
</DataGrid.Resources>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="GroupItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<StackPanel>
<TextBlock Text="{Binding Path=Name}" Background="DarkGray" Padding="2,0,0,0"/>
<ItemsPresenter/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Manager.ManagerName}" Header="Manager" />
<DataGridTextColumn Binding="{Binding Path=ProductName}" Header="Product" />
<DataGridTextColumn Binding="{Binding Path=MonitoringBy}" Header="Monitoring door" />
<DataGridTextColumn Binding="{Binding Path=AumProduct}" Header="AUM Product (mln)" />
<DataGridTextColumn Binding="{Binding Path=AumProductDate, StringFormat='{}{0:dd-MM-yyyy}'}" Header="Datum AUM Product" />
<DataGridTextColumn Binding="{Binding Path=AumStrategy}" Header="AUM Strategie (mln)" />
<DataGridTextColumn Binding="{Binding Path=AumStrategyDate, StringFormat='{}{0:dd-MM-yyyy}'}" Header="Datum AUM Strategie" />
<DataGridTextColumn Binding="{Binding Path=Aum}" Header="AUM (mln)" />
<DataGridTextColumn Binding="{Binding Path=TotalExpenseRatio}" Header="TER (bp)" />
<DataGridTextColumn Binding="{Binding Path=Fee}" Header="Total Fee" />
</DataGrid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Results.Count, StringFormat='{}{0} Producten'}" Grid.Column="0" Margin="0,0,0,0"/>
<Button Grid.Column="2"
Content="Toevoegen"
Padding="5,0,5,0" Margin="0,0,10,0"
Command="{Binding AddProductCommand}" />
<Button Grid.Column="3"
Content="Verwijderen"
Padding="5,0,5,0"
Command="{Binding Path=RemoveProductCommand}"
CommandParameter="{Binding Path=SelectedProduct}"/>
</Grid>
</Grid>
PageViewModel is an abstract class:
public abstract class PageViewModel: BaseViewModel
{
private int _pageProgress;
public int PageProgress
{
get { return _pageProgress; }
set
{
_pageProgress = value;
OnPropertyChanged("PageProgress");
}
}
}
It's kind of weird but it has something to do with the collectionviewsource (CvsAssetCategories) bound to the combobox. If I bind directly to the combobox without using the collectionviewsource the dependency property is not called. However, I like to use the collectionviewsource for the sortdescriptor. My solution now is a not null check on the setter from the dependency property, but I think its nasty way to go.

Categories