i have a template defiend as below:
<Window.Resources>
<DataTemplate x:Key="TemplateDetailView">
<Expander x:Name="exp" IsExpanded="True" FontSize="13" FontWeight="SemiBold">
<Expander.Header>
<TextBlock Foreground="{DynamicResource BlackColorBrush}">
<TextBlock.Text>
<MultiBinding StringFormat="{} {0} {1}">
<Binding Path="persons.Count"/>
<Binding Path="DisplayText"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Expander.Header>
<ListBox x:Name="lst" ItemsSource="{Binding persons}" Grid.Row="1" BorderThickness="0" Foreground="{DynamicResource BlackColorBrush}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border DataContext="{Binding}" BorderThickness="2" Margin="0,0,0,-1" BorderBrush="{DynamicResource NormalBorderBrush}" Visibility="{Binding IsVisibility}">
<DockPanel Margin="15,5" Background="Transparent">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Background="Transparent">
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" VerticalContentAlignment="Center" Tag="{Binding}" Padding="4,0" Style="{DynamicResource CheckBoxStyleDetailedViewStyle}" Checked="CheckBox_Checked" IsChecked="{Binding Acknowledged}" Height="30" Margin="3,5,3,3" Width="Auto"/>
</StackPanel> <ScrollViewer CanContentScroll="True" MinHeight="25" DockPanel.Dock="Left" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
<ItemsControl ScrollViewer.CanContentScroll="True" DataContext="{Binding}" ItemsSource="{Binding AlertActionsDefinition.Children}" x:Name="lstButton" ButtonBase.Click="lstButton_Click">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Background="Transparent" >
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Button Click="lstButton_Click" Content="{Binding Text}" Tag="{Binding}" Padding="4,0" IsEnabled="{Binding Visible}" Visibility="{Binding Visibility}" Height="30" Margin="3,5,3,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer> </StackPanel>
<Grid Width="700">
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Text}" Grid.Row="1" FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding Description}" Grid.Row="3" FontSize="13"/>
</Grid>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=lst,Path=Items.Count}" Value="0">
<Setter Property="Visibility" Value="Collapsed" TargetName="exp"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemTemplate="{DynamicResource TemplateShortView}" ItemsSource="{Binding}" BorderThickness="0">
</ListBox>
</Grid>
listbox is binded to class persons. initially the list box is loaded with short view which is then loaded to have detailed view template defined above. the problem i am facing is the click event on button inside template. click wont be fired at all some times and some times takes two to three clicks to raise the event.
could any one help me out to trace it down ?
I reduced your code to suit my testing and it works perfectly for me! I receive all the events correctly. In fact I receive lstButton_Click twice for each button clicked... (due to bubbling at Button and ItemsControl level).
Code Behind...
/// <summary>
/// Interaction logic for Window6.xaml
/// </summary>
public partial class Window6 : Window
{
public Window[] JustList
{
get
{
return new Window[] { this };
}
}
public List<Person> persons
{
get
{
return new List<Person>()
{
new Person()
{
Acknowledged = true,
Description = "Person 1",
Text = "Person1",
DisplayText = "I am Person 1"
},
new Person()
{
Acknowledged = true,
Description = "Person 2",
Text = "Person2",
DisplayText = "I am Person 2"
}
};
}
}
public Window6()
{
InitializeComponent();
}
void lstButton_Click(object sender, RoutedEventArgs e)
{
var i = 0 ;
}
void CheckBox_Checked(object sender, RoutedEventArgs e)
{
var i = 0;
}
}
public class Person
{
public string DisplayText { get; set; }
public string Text { get; set; }
public bool Acknowledged { get; set; }
public string Description { get; set; }
public Visibility IsVisibility { get; set; }
public List<Person> Children
{
get
{
return new List<Person>()
{
new Person()
{
Acknowledged = true,
Description = "Child 1",
Text = "Child1",
DisplayText = "My Child 1"
},
new Person()
{
Acknowledged = true,
Description = "Child 2",
Text = "Child2",
DisplayText = "My Child 2"
}
};
}
}
}
XAML ...
<Window.Resources>
<DataTemplate x:Key="TemplateDetailView">
<Expander x:Name="exp" IsExpanded="True"
FontSize="13" FontWeight="SemiBold">
<Expander.Header>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{} {0} {1}">
<Binding Path="persons.Count"/>
<Binding Path="DisplayText"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Expander.Header>
<ListBox x:Name="lst" ItemsSource="{Binding persons}"
Grid.Row="1" BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment"
Value="stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border DataContext="{Binding}"
BorderThickness="2"
Margin="0,0,0,-1" BorderBrush="Red">
<DockPanel Margin="15,5"
Background="Transparent">
<StackPanel DockPanel.Dock="Bottom"
Orientation="Horizontal"
Background="Transparent">
<StackPanel HorizontalAlignment="Left"
Orientation="Horizontal">
<CheckBox VerticalAlignment="Center"
VerticalContentAlignment="Center"
Tag="{Binding}"
Padding="4,0"
Checked="CheckBox_Checked"
IsChecked="{Binding Acknowledged}"
Height="30"
Margin="3,5,3,3" Width="Auto"/>
</StackPanel>
<ScrollViewer CanContentScroll="True"
MinHeight="25"
DockPanel.Dock="Left"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<ItemsControl
ScrollViewer.CanContentScroll="True"
DataContext="{Binding}"
ItemsSource="{Binding Children}"
x:Name="lstButton"
ButtonBase.Click="lstButton_Click">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"
Background="Transparent" >
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate >
<DataTemplate>
<Button Click="lstButton_Click"
Content="{Binding Text}"
Tag="{Binding}"
Padding="4,0"
IsEnabled="{Binding
Visible}"
Visibility="{Binding
Visibility}"
Height="30"
Margin="3,5,3,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
<Grid Width="700">
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Text}" Grid.Row="1"
FontWeight="Bold" FontSize="14"/>
<TextBlock Text="{Binding Description}"
Grid.Row="3" FontSize="13"/>
</Grid>
</DockPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=lst,Path=Items.Count}"
Value="0">
<Setter Property="Visibility" Value="Collapsed" TargetName="exp"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemTemplate="{StaticResource TemplateDetailView}"
ItemsSource="{Binding RelativeSource={RelativeSource
AncestorType={x:Type Window}},
Path=JustList}"
BorderThickness="0">
</ListBox>
</Grid>
Related
I am using .net core 3.1 in VS2019. I have a user control containing a ListView listing a set of items of a price list, each of them has a Cost, Markup (percent), a discount (percent) given by a related entity called Promotion and the SalePrice, FinalPrice and PromoDescription fields computed by converters. For example, FinalPrice equals SalePrice if the item does not have a promotion, or it is (SalePrice - SalePrice*item.Promotion.Discount/100.0) otherwise.
BTW, all of these entities belong to a EF Core model with lazy loading with proxies, and all the collections are ObervableCollection, which are loaded like the following:
var dbset = Context.Promos;
dbset.Load();
return dbset.Local.ToObservableCollection();
Everything works fine except when I change the Markup or the Promotion properties, which lead to recalculating the values provided by the converters and involving none or one related entity of type Promo. Debugging the windows I can see all the changes applied correctly in the underlying view model before and after they are confirmed to the database, however I have to force it to refresh the values as in the following picture.
This is the final composition of the window:
Window
TabControl
TabItem (n)
PriceListUserControl (my user control)
Here it is the model:
Here is the wpf of the user control containing the listview:
<UserControl x:Class="MyApp.View.UserControls.PriceListUserControl"
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:MyApp.View.UserControls"
xmlns:localModel="clr-namespace:MyApp.Model"
xmlns:localVm="clr-namespace:MyApp.ViewModel"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="UserControlPriceList">
<UserControl.Resources>
<localVm:PriceListItemConverter x:Key="priceListItemConverter"/>
<localVm:DateConverter x:Key="dateConverter"/>
<localVm:PromoConverter x:Key="promoConverter" />
<Border Style="{StaticResource BorderStyle}" Name="bottomBorder">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="106" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Producto:</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Costo:</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Markup (%):</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Precio de Lista:</TextBlock>
<TextBlock Grid.Row="4" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Promoción:</TextBlock>
<TextBlock Grid.Row="5" Grid.Column="0" Style="{StaticResource SmallTitleStyle}" Margin="5"> Precio Final:</TextBlock>
<TextBlock Name="ProductDescription" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=Product.Description}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
<TextBlock Name="CostPrice" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=Product.CostPrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
<TextBox Name="MarkupPriceEntryForm" AutomationProperties.Name="Markup" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
Style="{StaticResource TextStyleTextBox}" Margin="8,5,0,5" IsReadOnly="{Binding ElementName=UserControlPriceList, Path=DataContext.IsReadOnly}" >
<TextBox.Text>
<Binding Path="Markup" StringFormat="N2" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Name="SalePrice" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=SalePrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
<TextBlock Name="Promotion" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=PromoFriendlyDescription}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5"
Visibility="{Binding ElementName=UserControlPriceList, Path=DataContext.HideIfEditing}"/>
<ComboBox Name="PromosComboBox" AutomationProperties.Name="PromoDiscount" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left"
Text="(Seleccione promo)"
ItemsSource="{Binding ElementName=UserControlPriceList, Path=DataContext.PromoCollection}"
SelectedValue="{Binding ElementName=UserControlPriceList, Path=DataContext.Current.PromoId, Mode=TwoWay}"
SelectedValuePath="Id"
Style="{StaticResource ComboBoxStyle}"
ItemContainerStyle="{StaticResource ComboBoxItemStyle}" Margin="8,5,0,5"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
IsDropDownOpen="False"
StaysOpenOnEdit="True"
IsEditable="True" IsReadOnly="False"
Visibility="{Binding ElementName=UserControlPriceList, Path=DataContext.ShowIfEditing}"
Width="{Binding ElementName=Promotion, Path=Width}">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type localModel:Promo}">
<TextBlock Text="{Binding Converter={StaticResource promoConverter}, ConverterParameter=PromoFriendlyDescription}"/>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
<TextBlock Name="FinalPrice" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=FinalPrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Border Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MediumTitleStyle}" Margin="5"
Text="{Binding Path=List.Name, StringFormat='Lista: {0}'}" />
<TextBlock Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="2" Style="{StaticResource MediumTitleStyle}" Margin="5" HorizontalAlignment="Right"
Text="{Binding Path=List.PrintDate, StringFormat='Última impresión: {0:dd/MM/yyyy}'}" />
<Border Grid.Row="1" Style="{StaticResource BorderStyle}" Grid.ColumnSpan="4">
<ListView Name="ListViewPriceListItems" Grid.Row="1" Grid.ColumnSpan="4"
ItemsSource="{Binding Path=Items}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="OnPriceListItemSelectionChanged"
MouseDoubleClick="EnterPriceListItemEditMode"
IsEnabled="{Binding Path=IsReadOnly}">
<ListView.View>
<GridView AllowsColumnReorder="true" ColumnHeaderToolTip="Detalle de productos, precios finales y promociones">
<GridViewColumn DisplayMemberBinding="{Binding Path=Product.Description}" Header="Producto" Width="300"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Product.CostPrice, StringFormat=C}" Header="Costo"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Markup, StringFormat=N2}" Header="Markup (%)" />
<GridViewColumn DisplayMemberBinding="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=SalePrice, StringFormat=C}" Header="Precio Lista"/>
<GridViewColumn DisplayMemberBinding="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=PromoFriendlyDescription}" Header="Promoción" Width="200" />
<GridViewColumn DisplayMemberBinding="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=FinalPrice, StringFormat=C}" Header="Precio Final" />
</GridView>
</ListView.View>
</ListView>
</Border>
<ContentControl Name="PriceListDetail" Grid.Row="2" Grid.ColumnSpan="4"
Content="{Binding Path=Current}"
ContentTemplate="{StaticResource PriceListItemDetailTemplate}"
Margin="9,0,0,0" />
<StackPanel Grid.Row="3" Grid.ColumnSpan="4" Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="0,0,0,0"/>
</Style>
</StackPanel.Resources>
<Button Name="EditButton" HorizontalAlignment="Right" Content="_Modificar" Style="{StaticResource AcctionButtonStyle}"
ToolTip="Editar precio y promoción del producto seleccionado en esta lista."
Click="EditSelectedPriceListItem" Visibility="{Binding Path=HideIfEditing}"/>
<Button Name="SaveButton" HorizontalAlignment="Right" Content="_Aceptar" Style="{StaticResource ActionButtonOKStyle}"
ToolTip="Guardar los cambios realizados."
Click="SavePriceListItem" Visibility="{Binding Path=ShowIfEditing}"/>
<Button Name="CancelButton" HorizontalAlignment="Right" Content="_Cancelar" Style="{StaticResource ActionButtonCancelStyle}"
ToolTip="Deshacer los cambios realizados."
Click="UndoPriceListItem" Visibility="{Binding Path=ShowIfEditing}"/>
</StackPanel>
</Grid>
</Border>
This is its view model:
public partial class PriceListItemsViewModel: BaseViewModel<PriceListItem>
{
private PriceList _list;
public PriceListItemsViewModel(PriceList list, ObservableCollection<Promo> promoCollection)
{
this.List = list ?? throw new ArgumentNullException(nameof(list));
this.PromoCollection = promoCollection;
this.Items = list.Products;
this.IsEditMode = false;
this.IsNew = false;
this.Current = this.Items.FirstOrDefault();
}
public PriceList List { get => this._list; set => this._list = value; }
public ObservableCollection<Promo> PromoCollection { get; }
}
Note: BaseViewModel has an ObservableCollection, implements Generic INotifyPropertyChange, and common properties to indicate the current selected item in that collection and other useful states
And here the wpf of the view containing the previous user control:
<Window.Resources>
<uc:PriceListUserControl x:Key="userControlPList"/>
</Window.Resources>
<Border Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TabControl x:Name="TabControlPriceLists" Grid.Row="1" Grid.ColumnSpan="3" TabStripPlacement="Top"
ItemsSource="{Binding Items}"
SelectedItem="{Binding Current}"
IsEnabled="{Binding IsReadOnly}" >
<TabControl.Resources>
<DataTemplate DataType="{x:Type localVm:PriceListItemsViewModel}">
<uc:PriceListUserControl x:Name="UserControlPriceList"/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding List.Name}" />
<Setter Property="MaxWidth" Value="100" />
<Setter Property="ToolTip" Value="{Binding List.Name}" />
<Setter Property="Background" Value="Bisque" />
<Setter Property="FontWeight" Value="DemiBold" />
<EventSetter Event="MouseDoubleClick" Handler="OnTabItemDoubleClick"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Border>
And its view model:
public class PriceListsViewModel : BaseViewModel<PriceListItemsViewModel>
{
private ObservableCollection<Promo> promoCollection;
public PriceListsViewModel()
{
var promoDefaultItems = new List<Promo>
{
new Promo { FriendlyName = PromoConverter.PromoFriendlyNameNoPromo, DiscountPct = 0.0F } //Workaround: Adds "(No promo) to allow the user to left an item without promotion
//new Promo { FriendlyName = PromoConverter.PromoFriendlyNameNewPromo, DiscountPct = 0F }
};
this.promoCollection = new ObservableCollection<Promo>(promoDefaultItems);
var promos = PromoRepository.PromoGetAll();
foreach (var promo in promos)
{
this.promoCollection.Add(promo);
}
var lists = PriceListRepository.PriceListGetAll();
this.Items = new ObservableCollection<PriceListItemsViewModel>();
foreach (var l in lists)
{
this.Items.Add(new PriceListItemsViewModel(l, promoCollection));
}
this.IsEditMode = false;
this.IsNew = false;
this.Current = this.Items.FirstOrDefault();
}
}
I resolved the problem by creating a new view model wrapping the former PriceListItem and providing real properties and notifying their changes.
This is the new view model (only relevant code to show the new properties)
public class PriceListItemViewModel : SupervisedEntity
{
private PriceListItem _item;
public PriceListItemViewModel(PriceListItem item)
{
this._item = item ?? throw new ArgumentNullException(nameof(item));
//Bind the parent properties to its dependants (actually they are computed properties without setter) so they notify property changes when their parent property changes.
this.AddDependentProperty(nameof(this.PromoId), nameof(this.SalePrice));
this.AddDependentProperty(nameof(this.PromoId), nameof(this.FinalPrice));
this.AddDependentProperty(nameof(this.PromoId), nameof(this.PromoFriendlyDescription));
this.AddDependentProperty(nameof(this.Markup), nameof(this.SalePrice));
this.AddDependentProperty(nameof(this.Markup), nameof(this.FinalPrice));
}
// The properties and code not related to the solution were removed for clarity
public int? PromoId
{
get => this._item.PromoId;
set
{
this._item.PromoId = (value is null || value == 0) ? null : value;
this.NotifyPropertyChanged(); //This notifies not only the change in PromoId but also in all its dependent properties
}
}
public string ProductDescription => this._item.Product.Description;
public float CostPrice => this._item.Product.CostPrice;
[Required]
public float Markup
{
get => this._item.Markup;
set
{
this._item.Markup = value;
this.NotifyPropertyChanged();
}
}
//Using properties instead of extension methods allows me to create notification for them as dependent
public float SalePrice => this._item.SalePrice();
public float FinalPrice => this._item.FinalPrice();
public int Id => this.Item.Id;
public string PromoFriendlyDescription => this._item.PromoId is null ? string.Empty : this._item.Promotion.ToString();
}
And in the xaml of the user control I replaced all the converters, which didn't get notified when one of the properties they depended on changed, by the actual properties in the new view model.
First, replacing the class of the model by the new view model, like this:
<DataTemplate x:Key="PriceListItemDetailTemplate" DataType="{x:Type localVm:PriceListItemViewModel}">
And then replacing all the references to converters in the properties that change:
<TextBlock Name="SalePrice" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=SalePrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
<TextBlock Name="FinalPrice" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Converter={StaticResource priceListItemConverter}, ConverterParameter=FinalPrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
By the real properties in the new view model:
<TextBlock Name="SalePrice" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=SalePrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
<TextBlock Name="FinalPrice" Grid.Row="5" Grid.Column="1" HorizontalAlignment="Left"
Text="{Binding Path=FinalPrice, StringFormat=C}"
Style="{StaticResource TextStyleTextBlockTextBoxLike}" Margin="8,5,0,5" />
And now it works.
So I have a problem identical to this question.
However, the solution to this appears to be Code-Behind (and is 4 years old) but I am using MVVM. Time may have brought about a better solution to this.
Does anyone know of a way to have the double click work on a DataGridRow after it has been selected?
Here is my XAML:
<DataGrid x:Name="ContactsResult"
AlternatingRowBackground="Transparent"
AutoGenerateColumns="False"
BorderBrush="{StaticResource DarkBlueBrush}"
BorderThickness="1"
CanUserAddRows="False"
FontFamily="{StaticResource DefaultFont}"
GridLinesVisibility="None"
HeadersVisibility="Column"
IsReadOnly="True"
ItemsSource="{Binding Results, Mode=TwoWay}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
>
<DataGrid.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DetailsCommand}"
CommandParameter="{Binding ElementName=ContactsResult, Path=SelectedItem.ContactId}"
/>
</DataGrid.InputBindings>
<DataGrid.Columns>
<DataGridTextColumn x:Name="contactLastNameColumn"
Binding="{Binding Name_LastSufFirstMidSal}"
ElementStyle="{StaticResource dgCellPadding5}" Header="Contact Name"
Width="Auto"
/>
<DataGridTextColumn x:Name="companyNameColumn"
ElementStyle="{StaticResource dgCellPadding5}" Header="Company Name"
Width="Auto"
/>
<DataGridTextColumn x:Name="CityColumn"
Binding="{Binding MailingAddress.City}"
ElementStyle="{StaticResource dgCellPadding5}" Header="Mailing City"
Width="Auto"
/>
<DataGridTextColumn x:Name="StateColumn"
Binding="{Binding MailingAddress.StateOrProvince}" ElementStyle="{StaticResource dgCellPadding5}" Header="Mailing State"
Width="Auto"
/>
</DataGrid.Columns>
</DataGrid>
EDIT
ElementSytle
<Style x:Key="dgCellPadding5" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5" />
</Style>
The following sample, targeting .NET 4.7.1, fires double-click commands (regardless of selection status). I've included the style you referenced, from above. Is your code any different than this?
<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:wpfApp1="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<wpfApp1:ViewModel />
</Window.DataContext>
<Window.Resources>
<Style x:Key="dgCellPadding5" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="5" />
</Style>
</Window.Resources>
<DataGrid x:Name="ContactsResult"
AlternatingRowBackground="Transparent"
AutoGenerateColumns="False"
BorderThickness="1"
CanUserAddRows="False"
GridLinesVisibility="None"
HeadersVisibility="Column"
IsReadOnly="True"
ItemsSource="{Binding Contacts}"
SelectedItem="{Binding SelectedContact, Mode=TwoWay}">
<DataGrid.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding Command}"
CommandParameter="{Binding ElementName=ContactsResult, Path=SelectedItem}" />
</DataGrid.InputBindings>
<DataGrid.Columns>
<DataGridTextColumn ElementStyle="{StaticResource dgCellPadding5}"
Binding="{Binding ContactName}"
Header="Contact Name"
Width="Auto" />
<DataGridTextColumn ElementStyle="{StaticResource dgCellPadding5}" Header="Company Name"
Binding="{Binding CompanyName}"
Width="Auto" />
<DataGridTextColumn Binding="{Binding City}" Header="Mailing City"
Width="Auto" ElementStyle="{StaticResource dgCellPadding5}" />
<DataGridTextColumn Binding="{Binding State}" Header="Mailing State"
Width="Auto" ElementStyle="{StaticResource dgCellPadding5}" />
</DataGrid.Columns>
</DataGrid>
using System;
using System.Diagnostics;
using System.Windows.Input;
using Prism.Commands;
using Prism.Mvvm;
namespace WpfApp1
{
public class ViewModel : BindableBase
{
public ContactInfo[] Contacts
{
get;
} =
{
new ContactInfo
{
ContactName = "First",
CompanyName = "Acme",
City = "Somewhere",
State = "CA"
},
new ContactInfo
{
ContactName = "Second",
CompanyName = "Acme",
City = "Somewhere",
State = "CA"
},
new ContactInfo
{
ContactName = "Third",
CompanyName = "Acme",
City = "Somewhere",
State = "CA"
},
new ContactInfo
{
ContactName = "Fourth",
CompanyName = "Acme",
City = "Somewhere",
State = "CA"
}
};
private ContactInfo _selectedContact;
public ContactInfo SelectedContact
{
get => _selectedContact;
set => SetProperty(ref _selectedContact, value);
}
public ICommand Command
{
get;
} = new DelegateCommand<ContactInfo>(ci => Debug.WriteLine($"{ci.ContactName} {DateTime.Now}"));
public ICommand OtherCommand
{
get;
} = new DelegateCommand<string>(s => Debug.WriteLine($"{s} {DateTime.Now}"));
}
public class ContactInfo
{
public string ContactName
{
get;
set;
}
public string CompanyName
{
get; set;
}
public string City
{
get;
set;
}
public string State
{
get;
set;
}
}
}
I use Prism frame,this is my code :
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<controls:CustomDataGrid Grid.Row="2"
SelectedItem="{Binding ModelItem}"
ItemsSource="{Binding ModelList}"
IsReadOnly="True"
Style="{StaticResource DataTriggerDataGridStyle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding BtnNoticeViewCommand, IsAsync=True}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
So in order to reach my goal, I decided to go a different route.
First I started with a Grid and used the attribute Grid.IsSharedSizeScope="True". In this grid I created a grid and an ItemsControl (with a grid in the datatemplate). This gives me the appearance of a datagrid.
Second, in the itemscontrol I added InputBindings to each item to achieve the desired behaviour. Here is what I came up with:
<Border Grid.Row="2"
BorderBrush="{StaticResource BackgroundTitleBarBrush}"
BorderThickness="1"
Visibility="{Binding ResultGridVisible, Converter={local:BooleanToVisibilityValueConverter}, ConverterParameter=True}"
>
<Grid Background="White"
Grid.Row="2"
Grid.IsSharedSizeScope="True"
>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border BorderBrush="{StaticResource SeperatorDarkBlueBrush}"
BorderThickness="0 0 0 1"
Margin="5 0"
Padding="3 5"
Grid.Row="0">
<Grid VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A" Width="150"/>
<ColumnDefinition SharedSizeGroup="B" Width="200"/>
<ColumnDefinition SharedSizeGroup="C" Width="100"/>
<ColumnDefinition SharedSizeGroup="D" Width="75"/>
<ColumnDefinition SharedSizeGroup="E" Width="100"/>
<ColumnDefinition SharedSizeGroup="F" Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="0"
Text="Contact Name"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="1"
Text="Company Name"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="2"
Grid.ColumnSpan="2"
Text="Mailing"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="2"
Grid.Row="1"
Text="City"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="3"
Grid.Row="1"
Text="State"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="4"
Grid.ColumnSpan="2"
Text="Other"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="4"
Grid.Row="1"
Text="City"
/>
<TextBlock FontWeight="Bold"
Foreground="{StaticResource BackgroundTitleBarBrush}"
Grid.Column="5"
Grid.Row="1"
Text="State"
/>
</Grid>
</Border>
<ScrollViewer Grid.Row="1"
HorizontalScrollBarVisibility="Disabled"
MaxHeight="350"
VerticalScrollBarVisibility="Auto"
>
<ItemsControl ItemsSource="{Binding Results}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="Container"
BorderBrush="{StaticResource SeperatorLightBlueBrush}"
BorderThickness="0 0 0 1"
Margin="5 0"
Padding="3 5"
>
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding Path=DataContext.DetailsCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:BasePage}}}"
CommandParameter="{Binding ContactId}"
/>
<MouseBinding MouseAction="RightClick"
Command="{Binding Path=DataContext.NewWindowDetailsCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:BasePage}}}"
CommandParameter="{Binding ContactId}"
/>
</Border.InputBindings>
<Grid VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition SharedSizeGroup="B"/>
<ColumnDefinition SharedSizeGroup="C"/>
<ColumnDefinition SharedSizeGroup="D"/>
<ColumnDefinition SharedSizeGroup="E"/>
<ColumnDefinition SharedSizeGroup="F"/>
</Grid.ColumnDefinitions>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="0"
Text="{Binding Name_LastSufFirstMidSal}"
VerticalAlignment="Center"
/>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="1"
Text="{Binding Company}"
VerticalAlignment="Center"
/>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="2"
Text="{Binding MailingAddress.City}"
VerticalAlignment="Center"
/>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="3"
Text="{Binding MailingAddress.StateOrProvince}"
VerticalAlignment="Center"
/>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="4"
Text="{Binding OtherAddress.City}"
VerticalAlignment="Center"
/>
<TextBlock FontFamily="{StaticResource DefaultFont}"
Grid.Column="5"
Text="{Binding OtherAddress.StateOrProvince}"
VerticalAlignment="Center"
/>
</Grid>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Container" Property="Background" Value="{StaticResource BackgroundLightBlueBrush}"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Border Grid.Row="1" Panel.ZIndex="1" Visibility="{Binding NoRecordsFound, Converter={local:BooleanToCollapsedVisibilityValueConverter}, ConverterParameter=True, Mode=TwoWay}">
<TextBlock Text="No Records Found"
Margin="5 0"
Padding="3 5"
/>
</Border>
</Grid>
</Border>
Im using several controls in my main window.
one grid at top that has a list of licenses and i want to display the information of the license each time i change the selection of the grid
MainWindow:
<dx:DXWindow
x:Class="LicenceManagerWPF.Forms.frmCustomerLicense"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
dx:ThemeManager.ThemeName="Office2016"
xmlns:ctr="clr-namespace:LicenceManagerWPF.Controls"
Title="CustomerLicence" Height="800" Width="1000"
WindowStartupLocation="CenterScreen" Loaded="DXWindow_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition MinHeight="200" Height="200*"/>
<RowDefinition Height="200*"/>
<RowDefinition MinHeight="25" Height="25"/>
</Grid.RowDefinitions>
<StackPanel x:Name="Stack_Top" Orientation="Horizontal" Grid.Row="0" >
<dx:SimpleButton x:Name="btnRefresh" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Refresh Licenses" Glyph="{dx:DXImage Image=Refresh_32x32.png}" Content="Resfresh" />
<dx:SimpleButton x:Name="btndNew" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="New License" Glyph="{dx:DXImage Image=New_32x32.png}" Content="New Customer" />
<dx:SimpleButton x:Name="btnDelete" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Delete Licence" Content="Delete" Glyph="{dx:DXImage Image=Cancel_32x32.png}"/>
<dx:SimpleButton x:Name="btnEdit" Style="{StaticResource ResourceKey=BtnSmall}" ToolTip="Edit Customer" Glyph="{dx:DXImage Image=EditContact_32x32.png}" />
<TextBlock Text="Customer: " FontSize="20" Margin="5"/>
<TextBlock Text="{Binding Customer.Name}" Margin="5" FontSize="20"/>
</StackPanel>
<ctr:Licences x:Name="grdLicenses" Grid.Row="1">
</ctr:Licences>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ctr:LicenseDetail x:Name="ct_LicenseDetail" Grid.Column="0"/>
<ctr:LicenceLog x:Name="ct_LicenseLog" Grid.Column="1"/>
</Grid>
</Grid>
The grid is ctr_Licenses and the other control is LicenseDetail which should show the information of the license selected, this is the licenseDetail control:
<UserControl
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:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" x:Class="LicenceManagerWPF.Controls.LicenseDetail"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="600" x:Name="ctrl_LicenseDetail" >
<UserControl.Resources>
<Style x:Key="SmallMargin" TargetType="FrameworkElement">
<Setter Property="Margin" Value="5"/>
</Style>
<Style x:Key="TabMargin" TargetType="FrameworkElement" >
<Setter Property="Margin" Value="2.5"/>
</Style>
<Style x:Key="SmalllMarginTextBlock" BasedOn="{StaticResource SmallMargin}" TargetType="{x:Type TextBlock}">
</Style>
<Style x:Key="SmallMarginDropDown" BasedOn="{StaticResource SmallMargin }" TargetType="dx:DropDownButton" >
</Style>
<Style x:Key="SmallMarginText" BasedOn="{StaticResource SmallMargin}" TargetType="TextBox">
</Style>
<Style x:Key="ckkStyle" TargetType="dxe:CheckEdit" BasedOn="{StaticResource TabMargin}">
<Setter Property="IsReadOnly" Value="True"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30"/>
<RowDefinition Height="100*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="License Detail" FontSize="16" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="10" Grid.Row="0" />
<TextBlock Text="Serial Number:" Grid.Column="0" Grid.Row="1" Style="{StaticResource ResourceKey=SmalllMarginTextBlock}"/>
<TextBlock Text="{Binding Path=DataContext.SelectedLicense.SerialNumber, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=Window}}" x:Name="txtSerialNum" Grid.Column="1" Grid.Row="1" Style="{StaticResource ResourceKey=SmalllMarginTextBlock}"/>
<TextBlock Text="Product:" Grid.Column="0" Grid.Row="2" Style="{StaticResource ResourceKey=SmalllMarginTextBlock}" />
<StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="1">
<dx:DropDownButton x:Name="dropDownButton" Width="180" Content="Product" Style="{StaticResource SmallMarginDropDown}">
</dx:DropDownButton>
<TextBlock Text="Status:" Style="{StaticResource SmalllMarginTextBlock}" />
<TextBlock Text="" Width="150" Style="{StaticResource SmalllMarginTextBlock}" />
</StackPanel>
<TextBlock Text="Description:" Style="{StaticResource SmalllMarginTextBlock}" Grid.Row="3" Grid.Column="0" />
<TextBox Text="" HorizontalAlignment="Left" Grid.Column="1" Grid.Row="3" Style="{StaticResource SmallMargin}" Width="350" />
<dx:DXTabControl Grid.Row="4" Grid.ColumnSpan="2">
<dx:DXTabItem x:Name="tabAttributes" Header="License Attributes" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="Activation Mode:" Style="{StaticResource TabMargin}" />
<dx:DropDownButton Grid.Row="0" Grid.Column="1" Width="100" HorizontalAlignment="Left" Style="{StaticResource TabMargin}" ButtonKind="Repeat" />
<TextBlock Text="Grace Period:" Style="{StaticResource TabMargin}" Grid.Row="1"/>
<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
<dxe:SpinEdit Width="80" Style="{StaticResource TabMargin}" MinValue="0" MaxValue="100" IsReadOnly="True" Value="10" Mask="n0"/>
<TextBlock Text="Days" Style="{StaticResource TabMargin}" />
</StackPanel>
<dxe:CheckEdit Grid.Row="2" Content="Expiration Date" IsChecked="False" />
<dxe:DateNavigator Grid.Row="2" Grid.Column="1" Width="185" HorizontalAlignment="Left" Style="{StaticResource TabMargin}" />
<TextBlock Text="Max Computers:" Grid.Row="3" Style="{StaticResource TabMargin}"/>
<dxe:SpinEdit Grid.Row="4" Grid.Column="1" HorizontalAlignment="Left" Width="80" Margin="2.5,2.5,2.5,1" MinValue="0" MaxValue="100" IsReadOnly="True" Value="10" Mask="n0"/>
</Grid>
</dx:DXTabItem>
<dx:DXTabItem Header="Product Features" x:Name="tabProductFeatures" Visibility="Visible">
<StackPanel Orientation="Vertical" >
<dxe:CheckEdit Content="Standard" Name="chkStandard" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
<dxe:CheckEdit Content="Admin Mode" Name="chkAdminMode" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
<dxe:CheckEdit Content="Batch Mode" Name="chkBatchMode" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
<dxe:CheckEdit Content="Custom Data Series" Name="chkCustomDataSeries" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
<dxe:CheckEdit Content="Local DataBase" Name="LocalDataBase" IsReadOnly="True" IsChecked="True" Style="{StaticResource ckkStyle}"/>
<dxe:CheckEdit Content="Cloud Data Base" Name="CloudDataBase" Style="{StaticResource ckkStyle}" />
</StackPanel>
</dx:DXTabItem>
<dx:DXTabItem Name="tabComputers" Header="Computers">
<dxg:GridControl Name="grdComputers">
</dxg:GridControl>
</dx:DXTabItem>
<dx:DXTabItem Name="tabMain_Schedule" Header="Maint. Schedule">
<dxg:GridControl>
</dxg:GridControl>
</dx:DXTabItem>
<dx:DXTabItem x:Name="tabFeaturePB" Header="Product Features">
<StackPanel Orientation="Vertical">
<dxe:CheckEdit Content="pb" Name="chkpb" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
<dxe:CheckEdit Content="pb2" Name="chkpb2" IsReadOnly="True" Style="{StaticResource ckkStyle}" />
</StackPanel>
</dx:DXTabItem>
</dx:DXTabControl>
</Grid>
The DataContext class of the mainwindows is this
public class CustomerLicenses
{
private Customer _Customer;
private LicenseList _Licenses;
private License _SelectedLicense;
//private Guid _SelectedSerial;
//public delegate void SelectLicenseEventArg(String SerialNum);
//public event SelectLicenseEventArg SelectLicense;
public CustomerLicenses(Customer Customer)
{
_Customer = Customer;
}
public CustomerLicenses(Customer customer, LicenseList licenses)
{
_Customer = customer;
_Licenses = licenses;
}
public CustomerLicenses()
{
_Customer = new Customer();
_Licenses = new LicenseList();
}
[DataMember]
public Customer Customer
{
get { return _Customer; }
set
{
if (_Customer != value)
{
this._Customer = value;
this.NotifyPropertyChanged("Customer");
}
}
}
[DataMember]
public LicenseList Licenses
{
get { return _Licenses;}
set
{
if (_Licenses != value)
{
this._Licenses = value;
this.NotifyPropertyChanged("Licenses");
}
}
}
private DataTable GetLicensesTable()
{
var dt = new DataTable();
dt.Columns.AddRange(new DataColumn []{
new DataColumn("SerialNumber",typeof(string)),
new DataColumn("Product",typeof(string)),
new DataColumn("Status",typeof(string)),
new DataColumn("ActivationMode",typeof(string)),
new DataColumn("MaxComputers", typeof(int)),
new DataColumn("NumActive",typeof(int)),
new DataColumn("Description",typeof(string)),
new DataColumn("License",typeof(object))
});
_Licenses.ForEach((x) => {
var rw = dt.NewRow();
rw["SerialNumber"] = x.SerialNumber;
rw["Product"] = x.Product.Name;
rw["Status"] = x.Status;
rw["ActivationMode"] = Enum.GetName(typeof(ActivationModeEnum), x.ActivationMode); //x.ActivationMode;
rw["MaxComputers"] = x.MaxComputers;
rw["NumActive"] = Activated(x.Product.ProductId);
rw["Description"] = x.Description;
rw["License"] = x;
dt.Rows.Add(rw);
});
return dt;
}
public DataTable LicensesTable{
get { return GetLicensesTable(); }
}
[DataMember]
public License SelectedLicense {
get { return _SelectedLicense;}
set {
this.NotifyPropertyChanged("SelectedLicense");
_SelectedLicense = value;
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propName));
}
}
In this part im populating the textblock with the serial, and is ok it shows when i start the app `cause takes the first license but if i select another license the text does not change.
TextBlock Text="{Binding Path=DataContext.SelectedLicense.SerialNumber, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType=Window}}" x:Name="txtSerialNum" Grid.Column="1" Grid.Row="1" Style="{StaticResource ResourceKey=SmalllMarginTextBlock}"
This is how i assaing the value when the grid chanege selection
private void GridRowSelected (object sender, SelectedItemChangedEventArgs e)
{
try
{
var Record = (DataRowView)grdLicenses.grdLicences.SelectedItem;
var SelectedLicense = (License)Record["License"];
_CustomerLicense.SelectedLicense = SelectedLicense;
//Customer_Detail.DataContext = SelectedCustomer;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
How can i update the child when the item is selected in the grid.
Regards
sTrenat, as you said i checked the class and i was wrong implementing the propertyfotify
i changed to this
[DataContract]
public class CustomerLicenses: System.ComponentModel.INotifyPropertyChanged
{
public void NotifyPropertyChanged(string propName)
{
System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propName));
}
}
I have an itemscontrol that I used grouping on for a bunch for large colored buttons. I would like the groups to have a slight background to them that match the button color, whatever it might be (it's randomly defined by the user, but only if all the buttons in the group are the same. If all the buttons in the group do not have the same color, the background of the group should be transparent.
<DataTemplate x:Key="ButtonTemplate">
<Button Margin="0,0,8,8" Padding="0" Style="{StaticResource TileButton}" Command="{Binding NavigateToContentsCommand}">
<Grid Height="120" Width="271" Background="{Binding BackgroundBrush}">
<Grid Margin="30">
<TextBlock Grid.Column="1" Style="{StaticResource MediumHeader}" Text="{Binding Name}"/>
</Grid>
</Grid>
</Button>
</DataTemplate>
<ItemsPanelTemplate x:Key="ButtonPanel">
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
<ItemsControl ItemsSource="{Binding Items.View}" ItemTemplate="{StaticResource ButtonTemplate}" ItemsPanel="{StaticResource ButtonPanel}">
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Style="{StaticResource DetailsTextBlock}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Columns="{Binding Items.View.Groups.Count}"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GroupItem">
<Grid VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Background="{BINDING NOTSURE}" Opacity=".2"/>
<ContentPresenter Grid.Row="0"/>
<ItemsPresenter Grid.Row="1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ItemsControl.GroupStyle>
</ItemsControl>
Where I put the Binding not sure is where I got lost on how to proceed. I'm not sure if I need to examine the children of the group or how to go about that. Anyone have any experience with this?
Thanks!
Modify the border to trigger a loaded event
<Border x:Name="ColorBorder" Loaded="ColorBorder_Loaded" Grid.RowSpan="2" Opacity=".2"/>
Then add this event to loop through the items, if they exist.
private void ColorBorder_Loaded(object sender, RoutedEventArgs e)
{
Brush newBackgroundBrush = Brushes.Transparent;
try
{
var grid = VisualTreeHelper.GetParent((DependencyObject)sender);
GroupItem groupItem = VisualTreeHelper.GetParent(grid) as GroupItem;
CollectionViewGroup collectionViewGroup = (CollectionViewGroup)groupItem.Content;
if (collectionViewGroup.ItemCount > 0)
{
WorkstationNavigationViewModel.NavigationLevelViewModel navigationLevelViewModel = (WorkstationNavigationViewModel.NavigationLevelViewModel)collectionViewGroup.Items[0];
newBackgroundBrush = navigationLevelViewModel.BackgroundBrush;
for (int index = 1; index < collectionViewGroup.ItemCount; index++)
{
navigationLevelViewModel = (WorkstationNavigationViewModel.NavigationLevelViewModel)collectionViewGroup.Items[index];
if (navigationLevelViewModel.BackgroundBrush != newBackgroundBrush)
{
newBackgroundBrush = Brushes.Transparent;
break;
}
}
}
}
catch
{
newBackgroundBrush = Brushes.Transparent;
}
finally
{
Border border = (Border)sender;
border.Background = newBackgroundBrush;
}
}
I have a Listbox and a Border in a StackPanel similar to the following:
<StackPanel Orientation="Horizontal">
<ListBox>
<ListBoxItem Content="People"/>
<ListBoxItem Content="Animals"/>
<ListBoxItem Content="Cars"/>
</ListBox>
<Border Width="200>
<ContentPresenter/>
</Border>
</StackPanel>
When selecting an item in the listbox I would like to change the content in the ContentPresenter accordingly e.g. selecting People would change the template to display a series of input fields related to people where as selecting Animals would display a series of fields related to Animals etc. - the behavior of this would be akin to a TabControl.
I think I can achieve this with a DataTrigger which changes the DataTemplate in the Border but I'm not sure how to achieve this.
Any pointers?
Thanks
You can toggle the ContentTemplate using a DataTrigger as follows.
Note, that I am binding an ObservableCollection to a simple object (Thing) with one property called Name, and am I binding the Content of the ContentControl to the SelectedItem in the ListBox using a ViewModel.
<Grid>
<Grid.Resources>
<local:MultiValueConverter x:Key="con" />
<DataTemplate x:Key="PeopleTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="People Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="AnimalsTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="Animal Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CarsTemplate">
<StackPanel Orientation="Horizontal">
<Label Margin="0,0,5,0" Content="Car Name" HorizontalAlignment="Left" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100" Height="25"></TextBox>
<Button Content="OK" Grid.Column="2" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<ListBox ItemsSource="{Binding Things}" SelectedItem="{Binding SelectedThing}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0" Orientation="Horizontal">
<TextBlock Padding="5" Text="{Binding Name}" Margin="0"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Width="200">
<ContentControl Content="{Binding SelectedThing}">
<ContentControl.ContentTemplate>
<DataTemplate>
<ContentControl Name="cc"
Content="{Binding}"
ContentTemplate="{StaticResource PeopleTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Name}" Value="People">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource PeopleTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Name}" Value="Animals">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource AnimalsTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Name}" Value="Cars">
<Setter TargetName="cc"
Property="ContentTemplate"
Value="{StaticResource CarsTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</StackPanel>
<Grid>
Here is the Thing class:
public class Thing
{
public Thing(String name)
{
this.Name = name;
}
public String Name { get; set; }
public static ObservableCollection<Thing> GetThingList()
{
return new ObservableCollection<Thing>(new Thing[3] {
new Thing("People"),
new Thing("Animals"),
new Thing("Cars")
});
}
}